Talos Vulnerability Report

TALOS-2019-0841

SDL_image PCX Image Code execution Vulnerability

July 29, 2019
CVE Number

CVE-2019-5057

Summary

An exploitable code execution vulnerability exists in the PCX image-rendering functionality of SDL2_image 2.0.4. A specially crafted PCX image can cause a heap overflow, resulting in code execution. An attacker can display a specially crafted image to trigger this vulnerability.

Tested Versions

SDL_image 2.0.4

Product URLs

https://www.libsdl.org/projects/SDL_image/

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-122: Heap-based Buffer Overflow

Details

LibSDL is a multi-platform library for easy access to low-level hardware and graphics, providing support for a large number of video games, software and emulators. The LibSDL2_Image library is an optional component that deals specifically with parsing and displaying a variety of image file formats, creating a single, uniform API for image processing, regardless of the type.

When parsing a PCX image, SDL allocated a buffer to hold the pixels in the image sized to the parameters provided in the PCX image [0].

SDL/src/video/SDL_surface.c:112

/* Get the pixels */
if (surface->w && surface->h) {
    /* Assumptions checke   d in surface_size_assumptions assert above */
    Sint64 size = ((Sint64)surface->h * surface->pitch);
    if (size < 0 || size > SDL_MAX_SINT32) {
        /* Overflow... */
        SDL_FreeSurface(surface);
        SDL_OutOfMemory();
        return NULL;
    }

    surface->pixels = SDL_SIMDAlloc((size_t)size); [0]
    if (!surface->pixels) {
        SDL_FreeSurface(surface);
        SDL_OutOfMemory();
        return NULL;
    }

Later, the PCX header is read from the image into a PCXHeader struct [1].

SDL_image/Img_PCX.c:108
if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) { [1]
    error = "file truncated";
    goto done;
}

Using the data from this header, a number of bytes per line is calculated [2]. This bpl is used as a loop counter to populate a row or column buffer [3] based on a calculation also from the PCXHeader [4].

SDL_image/Img_PCX.c:42
struct PCXheader {
    Uint8 Manufacturer;
    Uint8 Version;
    Uint8 Encoding;
    Uint8 BitsPerPixel;
    Sint16 Xmin, Ymin, Xmax, Ymax;
    Sint16 HDpi, VDpi;
    Uint8 Colormap[48];
    Uint8 Reserved;
    Uint8 NPlanes;
    Sint16 BytesPerLine;
    Sint16 PaletteInfo;
    Sint16 HscreenSize;
    Sint16 VscreenSize;
    Uint8 Filler[54];
};

SDL_image/Img_PCX.c:122
src_bits = pcxh.BitsPerPixel * pcxh.NPlanes; [4]
...
bpl = pcxh.NPlanes * pcxh.BytesPerLine; [2]
if (bpl > surface->pitch) {
    error = "bytes per line is too large (corrupt?)";
}

buf = (Uint8 *)SDL_calloc(SDL_max(bpl, surface->pitch), 1);
row = (Uint8 *)surface->pixels;
for ( y=0; y<surface->h; ++y ) {
    /* decode a scan line to a temporary buffer first */
    int i, count = 0;
    Uint8 ch;
    Uint8 *dst = (src_bits == 8) ? row : buf; [3]
    if ( pcxh.Encoding == 0 ) {
        if(!SDL_RWread(src, dst, bpl, 1)) {
            error = "file truncated";
            goto done;
        }
    } else {
        for(i = 0; i < bpl; i++) {
            if(!count) {
                if(!SDL_RWread(src, &ch, 1, 1)) {
                    error = "file truncated";
                    goto done;
                }
                if( (ch & 0xc0) == 0xc0) {
                    count = ch & 0x3f;
                    if(!SDL_RWread(src, &ch, 1, 1)) {
                        error = "file truncated";
                        goto done;
                    }
                } else
                    count = 1;
            }
            dst[i] = ch; [5]
            count--;
        }
    }

If the correct bytes are set in the header to select the row buffer, an attacker can select the pixel buffer provided by SDL to populate. This population is controlled by the previous bytes per line calculation. An attacker can control this counter to write beyond the bounds of the heap buffer causing a heap based overflow potentially resulting in code execution.

Crash Information

=================================================================
==21589==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x607000000148 at pc 0x000000511489 bp 0x7ffd4f3378d0 sp 0x7ffd4f3378c8
WRITE of size 1 at 0x607000000148 thread T0
    #0 0x511488 in IMG_LoadPCX_RW /home/vagrant/fuzzing/SDL_image/build-afl-asan/../IMG_pcx.c:178:24
    #1 0x4ef64c in IMG_LoadTyped_RW /home/vagrant/fuzzing/SDL_image/build-afl-asan/../IMG.c:195:17
    #2 0x4ee16f in main /home/vagrant/fuzzing/SDL_image/build-afl-asan/../showimage.c:56:22
    #3 0x7f70518a182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x41a8a8 in _start (/ramdisk/SDL_image/build-afl-asan/showimage+0x41a8a8)

0x607000000148 is located 0 bytes to the right of 72-byte region [0x607000000100,0x607000000148)
allocated by thread T0 here:
    #0 0x4c15ac in malloc /scratch/llvm/clang-4/xenial/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:66:3
    #1 0x7f70527fd122 in SDL_malloc_REAL /home/vagrant/fuzzing/SDL/src/stdlib/SDL_malloc.c:5387:11

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/vagrant/fuzzing/SDL_image/build-afl-asan/../IMG_pcx.c:178:24 in IMG_LoadPCX_RW
Shadow bytes around the buggy address:
0x0c0e7fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c0e7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c0e7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c0e7fff8000: fa fa fa fa 00 00 00 00 00 00 00 00 07 fa fa fa
0x0c0e7fff8010: fa fa 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
0x0c0e7fff8020: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa <=
0x0c0e7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa

Timeline

2019-05-30 - Vendor Disclosure
2019-07-03 - Vendor Patched
2019-07-29 - Public Release

Credit

Discovered by Cory Duplantis of Cisco Talos.