Summary
stb_image's PNM loader in version v2.27 incorrectly interpreted 16-bit PGM files as 8-bit when converting to RGBA, leading to buffer overflow when later reinterpreting the result as a 16-bit buffer. An attacker could potentially have crashed a service using stb_image, or read up to 1024 bytes of non-consecutive heap data without control over the read location.
Describe the bug
In stb_image's PNM reader, loading a valid 16-bit PGM file that is large enough
with the number of components set to 4 can cause a crash in stbi__convert_16_to_8() due to an out-of-bounds read.
This issue includes a fix in pull request #1223, and a proof of concept file that
can be used to reproduce the crash. We're reporting this on GitHub Issues
following the guidance in issue #1213.
This appears to be due to how when stbi__pnm_load() loads a 16-bit PGM file
with N bytes of data, it incorrectly calls stbi__convert_format() instead of stbi__convert_format16(), returning a buffer that is 2N bytes long instead of
4N bytes. Since ri.bits_per_channel is still 16 when control returns to stbi__load_and_postprocess_8bit(), stbi__convert_16_to_8() attempts to read img_len=4N bytes of data from this buffer, resulting in out-of-bounds reads.
When N is large enough, this results in an access violation.
To Reproduce
This .zip contains a 513 KB .pgm file, 16_to_8_oob_poc.pgm, which reproduces this issue: 16_to_8_oob_poc.zip
Calling stbi_load() with a path to this file and with a req_comp of 4 produces a
crash. I was able to verify this using tests/image_test.c (modified slightly in
order to build) on Windows version 20H2 with Microsoft Visual Studio 2019, and
I expect it should reproduce on other systems as well.
This file was generated using the following Python script, and should be a valid PGM file:
f = open('16_to_8_oob_poc.pgm', 'wb')
f.write(b'P5\n\n512 512\n65535\n')
f.write(bytearray([1]*512*512*2))
f.close()
It was derived from an example found using the Radamsa fuzzer.
Interestingly, tests/pbm/basi0g16.pgm is also a 16-bit PGM file, but reading it
doesn't cause a crash! I believe the reason is because this is a 32 x 32 image,
so it only includes N=2048 bytes of image data, and as a result the out-of-bounds
reads don't cross a page boundary that would result in an access violation.
Expected behavior
The example file should be loaded without crashing.
Screenshots
Here's a screenshot showing where the crash occurs and the call stack, when run
with the example file in image_test.c. (Note that the call in image_test.c may
be off by 2 lines; the specific callsite is stbi_load(argv[i], &w, &h, &n, 4).)
Thanks!
The text was updated successfully, but these errors were encountered:
Fixes a crash and an infinite loop in stb_image that could occur with
specially constructed PGM and HDR files
nothings/stb#1223
This is a candidate fix for:
https://nvd.nist.gov/vuln/detail/CVE-2021-42715
In stb_image's HDR reader, loading a specially constructed invalid HDR
file can result in an infinite loop within the RLE decoder
nothings/stb#1224
Additionally, this is a candidate fix for:
https://nvd.nist.gov/vuln/detail/CVE-2021-42716
stbi__pnm_load heap-buffer-overflow bug
nothings/stb#1166
In stb_image's PNM reader, loading a specially constructed valid
16-bit PGM file with 4 channels can cause a crash due to an
out-of-bounds read
nothings/stb#1225
Summary
stb_image's PNM loader in version v2.27 incorrectly interpreted 16-bit PGM files as 8-bit when converting to RGBA, leading to buffer overflow when later reinterpreting the result as a 16-bit buffer. An attacker could potentially have crashed a service using stb_image, or read up to 1024 bytes of non-consecutive heap data without control over the read location.
CVE number: CVE-2021-42716
Describe the bug
In stb_image's PNM reader, loading a valid 16-bit PGM file that is large enough
with the number of components set to 4 can cause a crash in
stbi__convert_16_to_8()due to an out-of-bounds read.This issue includes a fix in pull request #1223, and a proof of concept file that
can be used to reproduce the crash. We're reporting this on GitHub Issues
following the guidance in issue #1213.
This appears to be due to how when
stbi__pnm_load()loads a 16-bit PGM filewith N bytes of data, it incorrectly calls
stbi__convert_format()instead ofstbi__convert_format16(), returning a buffer that is 2N bytes long instead of4N bytes. Since
ri.bits_per_channelis still 16 when control returns tostbi__load_and_postprocess_8bit(),stbi__convert_16_to_8()attempts to readimg_len=4Nbytes of data from this buffer, resulting in out-of-bounds reads.When N is large enough, this results in an access violation.
To Reproduce
This .zip contains a 513 KB .pgm file, 16_to_8_oob_poc.pgm, which reproduces this issue:
16_to_8_oob_poc.zip
Calling
stbi_load()with a path to this file and with a req_comp of 4 produces acrash. I was able to verify this using tests/image_test.c (modified slightly in
order to build) on Windows version 20H2 with Microsoft Visual Studio 2019, and
I expect it should reproduce on other systems as well.
This file was generated using the following Python script, and should be a valid PGM file:
It was derived from an example found using the Radamsa fuzzer.
Interestingly, tests/pbm/basi0g16.pgm is also a 16-bit PGM file, but reading it
doesn't cause a crash! I believe the reason is because this is a 32 x 32 image,
so it only includes N=2048 bytes of image data, and as a result the out-of-bounds
reads don't cross a page boundary that would result in an access violation.
Expected behavior
The example file should be loaded without crashing.
Screenshots
Here's a screenshot showing where the crash occurs and the call stack, when run
with the example file in image_test.c. (Note that the call in image_test.c may
be off by 2 lines; the specific callsite is
stbi_load(argv[i], &w, &h, &n, 4).)Thanks!
The text was updated successfully, but these errors were encountered: