Nothings/stb, an image processing library, has a Null Pointer Dereference vulnerability in the stbi__convert_format function, stb_image.h 2.28(https://github.com/nothings/stb/blob/master/stb_image.h). This function is called in stbi__pic_load and is used to parse files in the pic image format. And stbi__pic_load is called by stbi_load_from_memory.
static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
{
stbi_uc *result;
int i, x,y, internal_comp;
STBI_NOTUSED(ri);
if (!comp) comp = &internal_comp;
for (i=0; i<92; ++i)
stbi__get8(s);
x = stbi__get16be(s);
y = stbi__get16be(s);
if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
stbi__get32be(s); //skip `ratio'
stbi__get16be(s); //skip `fields'
stbi__get16be(s); //skip `pad'
// intermediate buffer is RGBA
result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
if (!result) return stbi__errpuc("outofmem", "Out of memory");
memset(result, 0xff, x*y*4);
if (!stbi__pic_load_core(s,x,y,comp, result)) {
STBI_FREE(result);
result=0;
}
*px = x;
*py = y;
if (req_comp == 0) req_comp = *comp;
result=stbi__convert_format(result,4,req_comp,x,y);
return result;
}
We can see that the "result" variable is assigned NULL after STBI_FREE and is used again by stbi__convert_format.
static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
unsigned char *good;
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
if (good == NULL) {
STBI_FREE(data);
return stbi__errpuc("outofmem", "Out of memory");
}
for (j=0; j < (int) y; ++j) {
unsigned char *src = data + j * x * img_n ;
unsigned char *dest = good + j * x * req_comp;
#define STBI__COMBO(a,b) ((a)*8+(b))
#define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
// convert source image with img_n components to one with req_comp components;
// avoid switch per pixel, so use switch per scanline and massive macros
switch (STBI__COMBO(img_n, req_comp)) {
STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break;
STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break;
STBI__CASE(2,1) { dest[0]=src[0]; } break;
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break;
STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break;
STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
}
#undef STBI__CASE
}
STBI_FREE(data);
return good;
}
The "result" variable will be used again as the "data" variable inside stbi__convert_format, when the "data" variable is already a null pointer, and using it again will result in a null pointer dereference.
The environment is shown below.
In the "null_example" folder, use the following command.
./build.sh
or
./example sample
We can see the "core dumped".
Denial of service attack
Here the "result" variable is assigned as a null pointer.
Here the null pointer is used as the base address, at which point an error occurs.