Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In stb_image's HDR reader, loading a specially constructed invalid HDR file can result in an infinite loop within the RLE decoder #1224

Closed
NBickford-NV opened this issue Oct 7, 2021 · 4 comments
Labels
1 stb_image 2 bug w/ repro 5 merged-dev Merged into development branch

Comments

@NBickford-NV
Copy link
Contributor

NBickford-NV commented Oct 7, 2021

Summary
stb_image's HDR loader in versions 1.33 to and including v2.27 parsed truncated end-of-file RLE scanlines as an infinite sequence of zero-length runs. An attacker could potentially have caused denial of service in applications using stb_image by submitting specially constructed HDR files.

CVE number: CVE-2021-42715

Describe the bug
In stb_image's HDR reader, loading a specially constructed invalid HDR file can
result in an infinite loop within the RLE decoder.

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.

The issue occurs in this loop within stbi__hdr_load():

while ((nleft = width - i) > 0) {
   count = stbi__get8(s);
   if (count > 128) {
      // Run
      value = stbi__get8(s);
      count -= 128;
      if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
      for (z = 0; z < count; ++z)
         scanline[i++ * 4 + k] = value;
   } else {
      // Dump
      if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
      for (z = 0; z < count; ++z)
         scanline[i++ * 4 + k] = stbi__get8(s);
   }
}

The proof of concept file manages to get this part of the decoder into a state
where:

  • nleft is equal to 11;
  • s is at the end of the file.

Because s is at the end of the file, stbi__get8() always returns 0, since
s->img_buffer == s->img_buffer_end here:

stbi_inline static stbi_uc stbi__get8(stbi__context *s)
{
   if (s->img_buffer < s->img_buffer_end)
      return *s->img_buffer++;
   if (s->read_from_callbacks) {
      stbi__refill_buffer(s);
      return *s->img_buffer++;
   }
   return 0;
}

This means that count is always set to 0; this passes the error check, but
doesn't affect any program state, meaning that the loop runs forever, an
availability issue.

To Reproduce
This .zip contains a 222 KB .hdr file, rle_iloop_poc.hdr, which reproduces this issue:
rle_iloop_poc.zip

Calling stbi_load() with a path to this file never returns. 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 found using the Radamsa fuzzer.
I think this particular file works by setting the RLE flags on the last scanline
in the file and being truncated in just the right place, but I'm not 100% sure.

Expected behavior
stbi_load should eventually return.

Based on Bruce Walter's
https://www.graphics.cornell.edu/~bjw/rgbe/rgbe.c HDR reader,
it seems like the intended behavior is that a run length of 0 should be treated
as invalid, which is the approach the pull request takes. However, other
solutions are possible (e.g. detecting when the end of the file has been reached) - I don't have any preference either way.

Thanks!

@nothings
Copy link
Owner

nothings commented Oct 7, 2021

Thank you for the report and the PR.

@NBickford-NV
Copy link
Contributor Author

Quick update: this has been assigned CVE number CVE-2021-42715. Thanks!

musicinmybrain added a commit to musicinmybrain/zxing-cpp that referenced this issue Dec 8, 2021
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
@rygorous
Copy link
Collaborator

Fixes merged into dev branch, will be in the next release.

@rygorous rygorous added the 5 merged-dev Merged into development branch label Jan 22, 2023
@rygorous
Copy link
Collaborator

Fixed in 2.28.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1 stb_image 2 bug w/ repro 5 merged-dev Merged into development branch
Projects
None yet
Development

No branches or pull requests

3 participants