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

heap-buffer-overflow in stbi__jpeg_load #1178

Closed
bufanremi opened this issue Jul 22, 2021 · 2 comments
Closed

heap-buffer-overflow in stbi__jpeg_load #1178

bufanremi opened this issue Jul 22, 2021 · 2 comments
Labels
1 stb_image 2 bug w/ repro 5 merged-dev Merged into development branch

Comments

@bufanremi
Copy link

poc.zip
I find heap-buffer-overflow in stbi__jpeg_load with lastest version: 2.27
clang test.cpp -fsanitize=address -o test
./test poc.jpg

ASAN log:

==11092==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62e00000b98f at pc 0x00000051515b bp 0x7ffe7ac04ea0 sp 0x7ffe7ac04e98
READ of size 1 at 0x62e00000b98f thread T0
    #0 0x51515a in stbi__resample_row_v_2(unsigned char*, unsigned char*, unsigned char*, int, int) (/home/test/stb/test+0x51515a)
    #1 0x511a00 in load_jpeg_image(stbi__jpeg*, int*, int*, int*, int) (/home/test/stb/test+0x511a00)
    #2 0x4e9039 in stbi__jpeg_load(stbi__context*, int*, int*, int*, int, stbi__result_info*) (/home/test/stb/test+0x4e9039)
    #3 0x4e294f in stbi__load_main(stbi__context*, int*, int*, int*, int, stbi__result_info*, int) (/home/test/stb/test+0x4e294f)
    #4 0x4d59fb in stbi__load_and_postprocess_8bit(stbi__context*, int*, int*, int*, int) (/home/test/stb/test+0x4d59fb)
    #5 0x4d5744 in stbi_load_from_file (/home/test/stb/test+0x4d5744)
    #6 0x4d5540 in stbi_load (/home/test/stb/test+0x4d5540)
    #7 0x4dbcc8 in main (/home/test/stb/test+0x4dbcc8)
    #8 0x7f9947da3bf6 in __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310
    #9 0x41b669 in _start (/home/test/stb/test+0x41b669)

0x62e00000b98f is located 0 bytes to the right of 46479-byte region [0x62e000000400,0x62e00000b98f)
allocated by thread T0 here:
    #0 0x4966ad in malloc /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
    #1 0x4d9c44 in stbi__malloc(unsigned long) (/home/test/stb/test+0x4d9c44)
    #2 0x4fbe26 in stbi__malloc_mad2(int, int, int) (/home/test/stb/test+0x4fbe26)
    #3 0x50ecd5 in stbi__process_frame_header(stbi__jpeg*, int) (/home/test/stb/test+0x50ecd5)
    #4 0x503133 in stbi__decode_jpeg_header(stbi__jpeg*, int) (/home/test/stb/test+0x503133)
    #5 0x514b69 in stbi__decode_jpeg_image(stbi__jpeg*) (/home/test/stb/test+0x514b69)
    #6 0x5101a8 in load_jpeg_image(stbi__jpeg*, int*, int*, int*, int) (/home/test/stb/test+0x5101a8)
    #7 0x4e9039 in stbi__jpeg_load(stbi__context*, int*, int*, int*, int, stbi__result_info*) (/home/test/stb/test+0x4e9039)
    #8 0x4e294f in stbi__load_main(stbi__context*, int*, int*, int*, int, stbi__result_info*, int) (/home/test/stb/test+0x4e294f)
    #9 0x4d59fb in stbi__load_and_postprocess_8bit(stbi__context*, int*, int*, int*, int) (/home/test/stb/test+0x4d59fb)
    #10 0x4d5744 in stbi_load_from_file (/home/test/stb/test+0x4d5744)
    #11 0x4d5540 in stbi_load (/home/test/stb/test+0x4d5540)
    #12 0x4dbcc8 in main (/home/test/stb/test+0x4dbcc8)
    #13 0x7f9947da3bf6 in __libc_start_main /build/glibc-S9d2JN/glibc-2.27/csu/../csu/libc-start.c:310

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/test/stb/test+0x51515a) in stbi__resample_row_v_2(unsigned char*, unsigned char*, unsigned char*, int, int)
Shadow bytes around the buggy address:
  0x0c5c7fff96e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5c7fff96f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5c7fff9700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5c7fff9710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c5c7fff9720: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c5c7fff9730: 00[07]fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5c7fff9740: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5c7fff9750: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5c7fff9760: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5c7fff9770: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c5c7fff9780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==11092==ABORTING

Analyze this bug:
In stbi_imgae.h version less than 2.27, the function load_jpeg_image will calculate the w_lores, and image_x, and in function stbi__process_frame_header, the will clac z->img_comp[i].w2, In some special h and v values, w_lores is
not equal to z->img_comp[k].w2, and load_jpeg_image will call r->resample to copy w_lores size , So it leads to oob read

rygorous added a commit that referenced this issue Jul 26, 2021
The component resamplers are not written to support this and I've
never seen it happen in a real (non-crafted) JPEG file so I'm
fine rejecting this as outright corrupt.

Fixes issue #1178.
@rygorous
Copy link
Collaborator

Thanks for the repro, fix for this issue is pushed to the dev branch and will be in the next release.

The underlying problem here is that the resampling code assumes that the plane resampling factors are integer factors (i.e. planes need to be upscaled by 2x, 3x or similar) and in this case the ratio works out to 1.5x; the calculation in stbi__process_frame_header calculates component sizes from the correct underlying ratios, whereas the actual resampling code computes an integer sampling ratio (rounding down) which yields different results.

All real JPEGs I've ever encountered have integer subsampling factors, so I just changed stbi__process_frame_header to check that the ratios indeed work out to integers and report the file as corrupt when they are not. It would not be hard to fix the calculation of w_lores but the resampler would then still be computing garbage because it's using an incorrect integer approximation to the actual subsampling factor, and making the resampler aware of arbitrary ratios would add a fair amount of complexity to support a feature that is very unlikely to ever occur outside of crafted/malicious files.

@rygorous rygorous added the 5 merged-dev Merged into development branch label Jul 26, 2021
rygorous added a commit that referenced this issue Jan 22, 2023
The component resamplers are not written to support this and I've
never seen it happen in a real (non-crafted) JPEG file so I'm
fine rejecting this as outright corrupt.

Fixes issue #1178.
@rygorous
Copy link
Collaborator

Fix was merged into master on Aug 13, 2021 and this bug wasn't closed, but it's fixed.

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

2 participants