diff --git a/CHANGES.rst b/CHANGES.rst index e85716f804f..fd8eca6efc4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,14 @@ Changelog (Pillow) ================== +6.2.2.1 (2021-10-08) +------------------ + +- This is the first Pillow release to support Python 2.7 from ActiveState + +- Catch SGI out-of-bounds reads. CVE 2020-11538 + [ucodery] + 6.2.2 (2020-01-02) ------------------ diff --git a/Tests/images/sgi_crash.bin b/Tests/images/sgi_crash.bin new file mode 100644 index 00000000000..9b138f6fe0a Binary files /dev/null and b/Tests/images/sgi_crash.bin differ diff --git a/Tests/images/sgi_overrun_expandrowF04.bin b/Tests/images/sgi_overrun_expandrowF04.bin new file mode 100644 index 00000000000..1907d5d3d47 Binary files /dev/null and b/Tests/images/sgi_overrun_expandrowF04.bin differ diff --git a/Tests/test_sgi_crash.py b/Tests/test_sgi_crash.py new file mode 100644 index 00000000000..93fc1464af3 --- /dev/null +++ b/Tests/test_sgi_crash.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +import pytest +from PIL import Image + + +def test_crashes(): + with open("Tests/images/sgi_crash.bin", "rb") as f: + im = Image.open(f) + with pytest.raises(IOError): + im.load() + + +def test_overrun_crashes(): + with open("Tests/images/sgi_overrun_expandrowF04.bin", "rb") as f: + im = Image.open(f) + with pytest.raises(IOError): + im.load() diff --git a/docs/releasenotes/6.2.2.1.rst b/docs/releasenotes/6.2.2.1.rst new file mode 100644 index 00000000000..8912fb798ad --- /dev/null +++ b/docs/releasenotes/6.2.2.1.rst @@ -0,0 +1,10 @@ +6.2.2.1 +------- + +Security +======== + +This release addresses CVE-2020-11538. + +CVE-2019-11538 is regarding SGI images. An out-of-bounds read can occur in the +parsing of SGI image files. diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index 770b604faf6..88ac182ecd3 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -6,6 +6,7 @@ Release Notes .. toctree:: :maxdepth: 2 + 6.2.2.1 6.2.2 6.2.1 6.2.0 diff --git a/src/PIL/_version.py b/src/PIL/_version.py index df16dce6036..d4fd833ad03 100644 --- a/src/PIL/_version.py +++ b/src/PIL/_version.py @@ -1,2 +1,2 @@ # Master version for Pillow -__version__ = "6.2.2" +__version__ = "6.2.2.1" diff --git a/src/libImaging/SgiRleDecode.c b/src/libImaging/SgiRleDecode.c index 1ba56b8c7b7..324353ce9ad 100644 --- a/src/libImaging/SgiRleDecode.c +++ b/src/libImaging/SgiRleDecode.c @@ -28,6 +28,7 @@ static void read4B(UINT32* dest, UINT8* buf) static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize) { UINT8 pixel, count; + int x = 0; for (;n > 0; n--) { @@ -37,9 +38,10 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize) count = pixel & RLE_MAX_RUN; if (!count) return count; - if (count > xsize) { + if (x + count > xsize) { return -1; } + x += count; if (pixel & RLE_COPY_FLAG) { while(count--) { *dest = *src++; @@ -62,6 +64,7 @@ static int expandrow(UINT8* dest, UINT8* src, int n, int z, int xsize) static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize) { UINT8 pixel, count; + int x = 0; for (;n > 0; n--) @@ -73,9 +76,10 @@ static int expandrow2(UINT8* dest, const UINT8* src, int n, int z, int xsize) count = pixel & RLE_MAX_RUN; if (!count) return count; - if (count > xsize) { + if (x + count > xsize) { return -1; } + x += count; if (pixel & RLE_COPY_FLAG) { while(count--) { memcpy(dest, src, 2);