From 7e95c63fa7f503f185d3d9eb16b9cee1e54d1e46 Mon Sep 17 00:00:00 2001
From: Eric Soroos <eric-github@soroos.net>
Date: Thu, 29 Oct 2020 23:07:15 +0000
Subject: [PATCH 1/3] Fix for SGI Decode buffer overrun CVE-2020-35655

* Independently found by a contributor and sent to Tidelift, and by Google's OSS Fuzz.
---
 ...7f2244da6d0ae297ee0754a424213444e92778.sgi | Bin 0 -> 6973 bytes
 Tests/images/ossfuzz-5730089102868480.sgi     | Bin 0 -> 530 bytes
 Tests/test_sgi_crash.py                       |   8 +++++-
 src/libImaging/SgiRleDecode.c                 |  23 ++++++++++++------
 4 files changed, 23 insertions(+), 8 deletions(-)
 create mode 100644 Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi
 create mode 100644 Tests/images/ossfuzz-5730089102868480.sgi

diff --git a/Tests/test_sgi_crash.py b/Tests/test_sgi_crash.py
index 2b671244a8..6626f55f7c 100644
--- a/Tests/test_sgi_crash.py
+++ b/Tests/test_sgi_crash.py
@@ -5,7 +5,13 @@
 
 @pytest.mark.parametrize(
     "test_file",
-    ["Tests/images/sgi_overrun_expandrowF04.bin", "Tests/images/sgi_crash.bin"],
+    [
+        "Tests/images/sgi_overrun_expandrowF04.bin",
+        "Tests/images/sgi_crash.bin",
+        "Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi",
+        "Tests/images/ossfuzz-5730089102868480.sgi",
+
+    ],
 )
 def test_crashes(test_file):
     with open(test_file, "rb") as f:
diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index a03ecd456e..46a9179234 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -107,11 +107,27 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
     int err = 0;
     int status;
 
+    /* size check */
+    if (im->xsize > INT_MAX / im->bands ||
+        im->ysize > INT_MAX / im->bands) {
+        return IMAGING_CODEC_MEMORY;
+    }
+
     /* Get all data from File descriptor */
     c = (SGISTATE*)state->context;
     _imaging_seek_pyFd(state->fd, 0L, SEEK_END);
     c->bufsize = _imaging_tell_pyFd(state->fd);
     c->bufsize -= SGI_HEADER_SIZE;
+
+    c->tablen = im->bands * im->ysize;
+    /* below, we populate the starttab and lentab into the bufsize,
+       each with 4 bytes per element of tablen
+       Check here before we allocate any memory
+    */
+    if (c->bufsize < 8*c->tablen) {
+        return IMAGING_CODEC_MEMORY;
+    }
+
     ptr = malloc(sizeof(UINT8) * c->bufsize);
     if (!ptr) {
         return IMAGING_CODEC_MEMORY;
@@ -129,18 +145,11 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
         state->ystep = 1;
     }
 
-    if (im->xsize > INT_MAX / im->bands ||
-        im->ysize > INT_MAX / im->bands) {
-        err = IMAGING_CODEC_MEMORY;
-        goto sgi_finish_decode;
-    }
-
     /* Allocate memory for RLE tables and rows */
     free(state->buffer);
     state->buffer = NULL;
     /* malloc overflow check above */
     state->buffer = calloc(im->xsize * im->bands, sizeof(UINT8) * 2);
-    c->tablen = im->bands * im->ysize;
     c->starttab = calloc(c->tablen, sizeof(UINT32));
     c->lengthtab = calloc(c->tablen, sizeof(UINT32));
     if (!state->buffer ||

From 9a2c9f722f78773e608d44710873437baf3f17d1 Mon Sep 17 00:00:00 2001
From: Eric Soroos <eric-github@soroos.net>
Date: Fri, 30 Oct 2020 09:57:23 +0000
Subject: [PATCH 2/3] Make the SGI code return -1 as an error flag, error in
 state

---
 src/libImaging/SgiRleDecode.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c
index 46a9179234..9a8814b50c 100644
--- a/src/libImaging/SgiRleDecode.c
+++ b/src/libImaging/SgiRleDecode.c
@@ -110,7 +110,8 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
     /* size check */
     if (im->xsize > INT_MAX / im->bands ||
         im->ysize > INT_MAX / im->bands) {
-        return IMAGING_CODEC_MEMORY;
+        state->errcode = IMAGING_CODEC_MEMORY;
+        return -1;
     }
 
     /* Get all data from File descriptor */
@@ -125,12 +126,14 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
        Check here before we allocate any memory
     */
     if (c->bufsize < 8*c->tablen) {
-        return IMAGING_CODEC_MEMORY;
+        state->errcode = IMAGING_CODEC_OVERRUN;
+        return -1;
     }
 
     ptr = malloc(sizeof(UINT8) * c->bufsize);
     if (!ptr) {
-        return IMAGING_CODEC_MEMORY;
+        state->errcode = IMAGING_CODEC_MEMORY;
+        return -1;
     }
     _imaging_seek_pyFd(state->fd, SGI_HEADER_SIZE, SEEK_SET);
     _imaging_read_pyFd(state->fd, (char*)ptr, c->bufsize);
@@ -178,7 +181,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
 
             if (c->rleoffset + c->rlelength > c->bufsize) {
                 state->errcode = IMAGING_CODEC_OVERRUN;
-                return -1;
+                goto sgi_finish_decode;
             }
 
             /* row decompression */
@@ -190,7 +193,7 @@ ImagingSgiRleDecode(Imaging im, ImagingCodecState state,
             }
             if (status == -1) {
                 state->errcode = IMAGING_CODEC_OVERRUN;
-                return -1;
+                goto sgi_finish_decode;
             } else if (status == 1) {
                 goto sgi_finish_decode;
             }
@@ -211,7 +214,8 @@ sgi_finish_decode: ;
     free(c->lengthtab);
     free(ptr);
     if (err != 0){
-        return err;
+        state->errcode=err;
+        return -1;
     }
     return state->count - c->bufsize;
 }

From 1cbb12fb6e44da0d6d6d58254d0d96930d04af5e Mon Sep 17 00:00:00 2001
From: Andrew Murray <radarhere@users.noreply.github.com>
Date: Sat, 2 Jan 2021 20:19:26 +1100
Subject: [PATCH 3/3] Lint fix

---
 Tests/test_sgi_crash.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Tests/test_sgi_crash.py b/Tests/test_sgi_crash.py
index 6626f55f7c..ac304aab4d 100644
--- a/Tests/test_sgi_crash.py
+++ b/Tests/test_sgi_crash.py
@@ -10,7 +10,6 @@
         "Tests/images/sgi_crash.bin",
         "Tests/images/crash-6b7f2244da6d0ae297ee0754a424213444e92778.sgi",
         "Tests/images/ossfuzz-5730089102868480.sgi",
-
     ],
 )
 def test_crashes(test_file):
