From 00f3f01be387fa7cba07eabec6f01441ccfa30a5 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 27 Apr 2020 14:54:58 -0400 Subject: [PATCH] fseek() resets the EOF flag, even if seeking past the end of a read-only file. This causes problems when stb_image tries to do this with stdio callbacks with a maliciously crafted file (or just an unfortunately corrupt one)... // calls fread(), sets EOF flag, sets s->read_from_callbacks = 0 stbi__refill_buffer(s); // calls fseek(), which resets the stream's EOF flag stbi__skip(some value we just read) // calls feof(), which always returns false because EOF flag was reset. while (!stbi__at_eof(s)) { // never calls fread() because s->read_from_callbacks==0 stbi__refill_buffer(s); // loop forever } To work around this, after seeking, we call fgetc(), which will set the EOF flag as appropriate, and if not at EOF, we ungetc the byte so future reads are correct. This fixes the infinite loop. --- stb_image.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/stb_image.h b/stb_image.h index 2857f05..6f079ab 100644 --- a/stb_image.h +++ b/stb_image.h @@ -789,7 +789,12 @@ static int stbi__stdio_read(void *user, char *data, int size) static void stbi__stdio_skip(void *user, int n) { + int ch; fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } } static int stbi__stdio_eof(void *user)