Headline
CVE-2023-37748: Infinite loop has occurred when running program gif2tga in function DecodeGifImg at ngiflib.c · Issue #25 · miniupnp/ngiflib
ngiflib commit 5e7292 was discovered to contain an infinite loop via the function DecodeGifImg at ngiflib.c.
Desctiption
Infinite loop has occurred when running program gif2tga in function DecodeGifImg at ngiflib.c:556
Version
commit 5e7292bfabbeeee8dca0bf4c9a77ff10c8e3bf28 (HEAD -> master, origin/master, origin/HEAD)
Author: Thomas Bernard <[email protected]>
Date: Thu Jun 29 01:57:28 2023 +0200
Steps to reproduce
git clone https://github.com/miniupnp/ngiflib.git
cd ngiflib
CC="clang -fsanitize=address -g" CFLAGS+=-DNGIFLIB_NO_FILE make
./gif2tga -i ./poc2
POC
https://github.com/GGb0ndQAQ/POC/blob/main/ngiflib/poc2
Code in ngiflib.c:556
for(;;) { // here
act_code = GetGifWord(i, &context);
printf("%d - %d - %d\n",act_code, i->parent->input.buffer.count, npix);
if(act_code==eof) {
#if !defined(NGIFLIB_NO_FILE)
if(i->parent && i->parent->log) fprintf(i->parent->log, "End of image code 0x%x (nbbit=%u)\n", eof, context.nbbit);
#endif /* !defined(NGIFLIB_NO_FILE) */
return 0;
}
if(npix==0) {
#if !defined(NGIFLIB_NO_FILE)
if(i->parent && i->parent->log) fprintf(i->parent->log, "assez de pixels, On se casse !\n");
#endif /* !defined(NGIFLIB_NO_FILE) */
return 1;
}
if(act_code==clr) {
#if !defined(NGIFLIB_NO_FILE)
if(i->parent && i->parent->log) fprintf(i->parent->log, "Code clear (%hu) (free=%hu) npix=%ld\n", clr, free, npix);
#endif /* !defined(NGIFLIB_NO_FILE) */
/* clear */
free = clr + 2;
context.nbbit = i->imgbits + 1;
context.max = clr + clr - 1; /* (1 << context.nbbit) - 1 */
act_code = GetGifWord(i, &context); /* the first code after the clear code is concrete */
if (act_code >= clr)
{
#if !defined(NGIFLIB_NO_FILE)
if(i->parent && i->parent->log) fprintf(i->parent->log, "Invalid code %hu just after clear(%hu) !\n", act_code, clr);
#endif /* !defined(NGIFLIB_NO_FILE) */
return -1;
}
casspecial = (u8)act_code;
old_code = act_code;
if(npix > 0) WritePixel(i, &context, casspecial);
npix--;
} else if(act_code > free) {
#if !defined(NGIFLIB_NO_FILE)
if(i->parent && i->parent->log) fprintf(i->parent->log, "Invalid code %hu (free=%hu) !\n", act_code, free);
#endif /* !defined(NGIFLIB_NO_FILE) */
return -1;
} else {
read_byt = act_code;
if(act_code == free) { /* code pas encore dans alphabet */
/* printf("Code pas dans alphabet : %d>=%d push %d\n", act_code, free, casspecial); */
*(--stackp) = casspecial; /* dernier debut de chaine ! */
act_code = old_code;
}
/* printf("actcode=%d\n", act_code); */
while(act_code > clr) { /* code non concret */
/* fillstackloop empile les suffixes ! */
*(--stackp) = ab_suffx[act_code];
act_code = ab_prfx[act_code]; /* prefixe */
}
/* act_code est concret */
casspecial = (u8)act_code; /* dernier debut de chaine ! */
*(--stackp) = casspecial; /* push on stack */
if(npix >= (stack_top - stackp)) {
WritePixels(i, &context, stackp, stack_top - stackp); /* unstack all pixels at once */
} else if(npix > 0) { /* "pixel overflow" */
WritePixels(i, &context, stackp, npix);
}
npix -= (stack_top - stackp);
stackp = stack_top;
/* putchar('\n'); */
if(free < 4096) { /* la taille du dico est 4096 max ! */
ab_prfx[free] = old_code;
ab_suffx[free] = (u8)act_code;
free++;
if((free > context.max) && (context.nbbit < 12)) {
context.nbbit++; /* 1 bit de plus pour les codes LZW */
context.max += context.max + 1;
}
}
old_code = read_byt;
}
}
Impact
Potentially causing DoS