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

An infinite loop in png_read_png->..->png_write_row #492

Open
PromptFuzz opened this issue Aug 30, 2023 · 4 comments
Open

An infinite loop in png_read_png->..->png_write_row #492

PromptFuzz opened this issue Aug 30, 2023 · 4 comments

Comments

@PromptFuzz
Copy link

Summary

A infinite loop bug found in png_read_png.
Remote attackers could leverage this vulnerability to cause a denial-of-service via a crafted PNG file.

POC

#include <png.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <vector>
#include <fstream>
#include <iostream>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {

    // Initialize libpng variables
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop info_ptr = png_create_info_struct(png_ptr);

    // Create a FILE pointer to read the input data
    FILE *in_file = fmemopen((void *)data, size, "rb");
    
    // Set up the read callback function
    png_set_read_fn(png_ptr, (png_voidp)in_file, [](png_structp png_ptr, png_bytep data, png_size_t length) {
        fread(data, 1, length, (FILE *)png_get_io_ptr(png_ptr));
    });
    
    // Read the PNG image
    png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
  
  return 0;
}

POC input

timeout-f74021412fba530904cddd63e3033f1527d52d76

Version

Found on version of 2023/06/07. Reproducible on the master branch.

Compile commands

# export the flags.
    SANITIZER_FLAGS="-O2 -fsanitize=address,undefined -fsanitize-address-use-after-scope -g "
    FUZZER_FLAGS="-fsanitize=fuzzer-no-link -fno-omit-frame-pointer -g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION $SANITIZER_FLAGS"
    export CFLAGS="${CFLAGS:-} $FUZZER_FLAGS"
    export CXXFLAGS="${CXXFLAGS:-} $FUZZER_FLAGS"
# build the libpng library.
    cd $SRC/libpng
    autoreconf -f -i
    ./configure
    make -j$(nproc) clean
    make -j$(nproc) libpng16.la

Compile the poc program

clang++ -fsanitize=fuzzer -O0 -g -fsanitize=address,undefined -ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -I/src/libpng/include  poc.cc -o test.out /src/libpng/lib/libpng16.so

Reproduce Step

./test.out timeout-f74021412fba530904cddd63e3033f1527d52d76

Additional Information

When the variable i = 0xff (image_height = 0x100) in the loop from lines 751-755, the png_read_row(png_ptr, *rp, NULL); will hang.

//pngread.c
void PNGAPI
png_read_image(png_structrp png_ptr, png_bytepp image) {
...
   for (j = 0; j < pass; j++)
   {
      rp = image;
751      for (i = 0; i < image_height; i++)
752      {
753        png_read_row(png_ptr, *rp, NULL);
754        rp++;
755      }
   }

The program finally hang at the below loop.

png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
    png_alloc_size_t avail_out)
{
...
   do
   {
      ... // hang
  }while (avail_out > 0);

Stack trace

...
[#3] 0x7ffff76278d4 → png_read_IDAT_data(png_ptr=0x61a000000080, output=0x0, avail_out=0x91bd0800)
[#4] 0x7ffff7628f13 → png_read_finish_IDAT(png_ptr=0x61a000000080)
[#5] 0x7ffff762c960 → png_read_finish_row(png_ptr=0x61a000000080)
[#6] 0x7ffff74cc279 → png_read_row(png_ptr=0x61a000000080, row=0x617000037d00 "\003\002\001\006\004\002\t\006\003\f\b\004\017\n\005\022\f\006\025\016\a\030\020\b\033\022\t\036\024\n!\026\v$\030\f'\032\r*\034\016-\036\0170 \0203\"\0216$\0229&\023<(\024?*\025B,\026E.\027H0\030K2\031N4\032Q6\033T8\034W:\035Z<\036]>\037`@ cB!fD\"iF#lH$oJ%rL&uN'xP({R)~T*\201V+\204X,\207Z-\212\\.\215^/\220`0\223b1\226d2\231f3\234h4\237j5\242l6\245n7\250p8\253r9\256t:\261v;\264x<\267z=\272|>\275~?\300\200@ÂAƄBɆC̈DϊEҌFՎGؐHےIޔJ\341\226K\344\230L\347\232M\352\234N\355\236O\360\240P\363\242Q\366\244R\371\246S\374\250T\377\252U\002\254V\005\256W\b\260X\v\262Y\016\264Z\021\266[\024\270\\\027\272]\032\274^\035\276_ \300`#\302a&\304b)\306c,\310d/\312e2\314f5\316g8\320h;\322i>\324jA\326kD\330lG\332mJ\334nM\336oP\340pS\342qV\344rY\346s\\\350t_\352ub\354ve\356wh\360xk\362yn\364zq\366{t\370|w\372}z\374~}\376\177\200", dsp_row=0x0)
[#7] 0x7ffff74d050f → png_read_image(png_ptr=0x61a000000080, image=0x61d000000080)
[#8] 0x7ffff74d805e → png_read_png(png_ptr=0x61a000000080, info_ptr=0x6130000003c0, transforms=0x0, params=0x0)
[#9] 0x5555556d8ef4 → LLVMFuzzerTestOneInput(data=0x613000000200 "\211PNG\r\n\032\n", size=0x160)
@PromptFuzz PromptFuzz changed the title A infinite loop in png_read_png->..->png_write_row An infinite loop in png_read_png->..->png_write_row Aug 30, 2023
@jbowler
Copy link
Member

jbowler commented Dec 23, 2023

I suggest you submit a small program and the input file that will repro this. As reported the bug is incredible.

@PromptFuzz
Copy link
Author

@jbowler
Hi, I have provided the PoC program and PoC input at:
timeout_poc.tar.gz

You can reproduce this issue by running:
poc.out timeout-f74021412fba530904cddd63e3033f1527d52d76

@jbowler
Copy link
Member

jbowler commented Dec 28, 2023

@jbowler Hi, I have provided the PoC program and PoC input at: [timeout_poc.tar.gz]

You need to remove that file, it is reported by Chrome as containing a virus. I've separately reported this to github.com

Please do not post compiled programs here. They are not useful in bug reports. What I'm asking for is a simple example which compiles, links, runs and demonstrates the problem. A program of this size is likely to be inappropriate even if you provide the source code.

@jbowler
Copy link
Member

jbowler commented Dec 28, 2023

But apart from that your code is wrong; your read function does no error handling so when it reaches the end of the file (which it does because the enormous IDAT at the end is truncated) it just keeps on reading.

@ctruta: application bug (bad read function)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants