Skip to content

Commit 782d29a

Browse files
committed
Fixed TALOS-2019-0841, heap buffer overlow exploit
Also fixed loading some images with incorrect palette location
1 parent 144b919 commit 782d29a

File tree

1 file changed

+53
-29
lines changed

1 file changed

+53
-29
lines changed

IMG_pcx.c

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,16 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
9898
Uint8 *row, *buf = NULL;
9999
char *error = NULL;
100100
int bits, src_bits;
101+
int count = 0;
102+
Uint8 ch;
101103

102104
if ( !src ) {
103105
/* The error message has been set in SDL_RWFromFile */
104106
return NULL;
105107
}
106108
start = SDL_RWtell(src);
107109

108-
if ( ! SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
110+
if ( !SDL_RWread(src, &pcxh, sizeof(pcxh), 1) ) {
109111
error = "file truncated";
110112
goto done;
111113
}
@@ -115,6 +117,20 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
115117
pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
116118
pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
117119

120+
#if 0
121+
printf("Manufacturer = %d\n", pcxh.Manufacturer);
122+
printf("Version = %d\n", pcxh.Version);
123+
printf("Encoding = %d\n", pcxh.Encoding);
124+
printf("BitsPerPixel = %d\n", pcxh.BitsPerPixel);
125+
printf("Xmin = %d, Ymin = %d, Xmax = %d, Ymax = %d\n", pcxh.Xmin, pcxh.Ymin, pcxh.Xmax, pcxh.Ymax);
126+
printf("HDpi = %d, VDpi = %d\n", pcxh.HDpi, pcxh.VDpi);
127+
printf("NPlanes = %d\n", pcxh.NPlanes);
128+
printf("BytesPerLine = %d\n", pcxh.BytesPerLine);
129+
printf("PaletteInfo = %d\n", pcxh.PaletteInfo);
130+
printf("HscreenSize = %d\n", pcxh.HscreenSize);
131+
printf("VscreenSize = %d\n", pcxh.VscreenSize);
132+
#endif
133+
118134
/* Create the surface of the appropriate type */
119135
width = (pcxh.Xmax - pcxh.Xmin) + 1;
120136
height = (pcxh.Ymax - pcxh.Ymin) + 1;
@@ -144,51 +160,52 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
144160
goto done;
145161

146162
bpl = pcxh.NPlanes * pcxh.BytesPerLine;
147-
if (bpl > surface->pitch) {
163+
if ( bpl > surface->pitch ) {
148164
error = "bytes per line is too large (corrupt?)";
165+
goto done;
149166
}
150-
buf = (Uint8 *)SDL_calloc(SDL_max(bpl, surface->pitch), 1);
167+
buf = (Uint8 *)SDL_calloc(surface->pitch, 1);
151168
row = (Uint8 *)surface->pixels;
152169
for ( y=0; y<surface->h; ++y ) {
153170
/* decode a scan line to a temporary buffer first */
154-
int i, count = 0;
155-
Uint8 ch;
156-
Uint8 *dst = (src_bits == 8) ? row : buf;
171+
int i;
172+
Uint8 *dst = buf;
157173
if ( pcxh.Encoding == 0 ) {
158-
if(!SDL_RWread(src, dst, bpl, 1)) {
174+
if ( !SDL_RWread(src, dst, bpl, 1) ) {
159175
error = "file truncated";
160176
goto done;
161177
}
162178
} else {
163-
for(i = 0; i < bpl; i++) {
164-
if(!count) {
165-
if(!SDL_RWread(src, &ch, 1, 1)) {
179+
for ( i = 0; i < bpl; i++ ) {
180+
if ( !count ) {
181+
if ( !SDL_RWread(src, &ch, 1, 1) ) {
166182
error = "file truncated";
167183
goto done;
168184
}
169-
if( (ch & 0xc0) == 0xc0) {
170-
count = ch & 0x3f;
171-
if(!SDL_RWread(src, &ch, 1, 1)) {
185+
if ( ch < 0xc0 ) {
186+
count = 1;
187+
} else {
188+
count = ch - 0xc0;
189+
if( !SDL_RWread(src, &ch, 1, 1) ) {
172190
error = "file truncated";
173191
goto done;
174192
}
175-
} else
176-
count = 1;
193+
}
177194
}
178195
dst[i] = ch;
179196
count--;
180197
}
181198
}
182199

183-
if(src_bits <= 4) {
200+
if ( src_bits <= 4 ) {
184201
/* expand planes to 1 byte/pixel */
185202
Uint8 *innerSrc = buf;
186203
int plane;
187-
for(plane = 0; plane < pcxh.NPlanes; plane++) {
204+
for ( plane = 0; plane < pcxh.NPlanes; plane++ ) {
188205
int j, k, x = 0;
189-
for(j = 0; j < pcxh.BytesPerLine; j++) {
206+
for( j = 0; j < pcxh.BytesPerLine; j++ ) {
190207
Uint8 byte = *innerSrc++;
191-
for(k = 7; k >= 0; k--) {
208+
for( k = 7; k >= 0; k-- ) {
192209
unsigned bit = (byte >> k) & 1;
193210
/* skip padding bits */
194211
if (j * 8 + k >= width)
@@ -197,46 +214,53 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
197214
}
198215
}
199216
}
200-
} else if(src_bits == 24) {
217+
} else if ( src_bits == 24 ) {
201218
/* de-interlace planes */
202219
Uint8 *innerSrc = buf;
203220
int plane;
204-
for(plane = 0; plane < pcxh.NPlanes; plane++) {
221+
for ( plane = 0; plane < pcxh.NPlanes; plane++ ) {
205222
int x;
206223
dst = row + plane;
207-
for(x = 0; x < width; x++) {
224+
for ( x = 0; x < width; x++ ) {
225+
if ( dst >= row+surface->pitch ) {
226+
error = "decoding out of bounds (corrupt?)";
227+
goto done;
228+
}
208229
*dst = *innerSrc++;
209230
dst += pcxh.NPlanes;
210231
}
211232
}
233+
} else {
234+
SDL_memcpy(row, buf, bpl);
212235
}
213236

214237
row += surface->pitch;
215238
}
216239

217-
if(bits == 8) {
240+
if ( bits == 8 ) {
218241
SDL_Color *colors = surface->format->palette->colors;
219242
int nc = 1 << src_bits;
220243
int i;
221244

222245
surface->format->palette->ncolors = nc;
223-
if(src_bits == 8) {
246+
if ( src_bits == 8 ) {
224247
Uint8 ch;
225248
/* look for a 256-colour palette */
226249
do {
227-
if ( !SDL_RWread(src, &ch, 1, 1)) {
228-
error = "file truncated";
229-
goto done;
250+
if ( !SDL_RWread(src, &ch, 1, 1) ) {
251+
/* Couldn't find the palette, try the end of the file */
252+
SDL_RWseek(src, -768, RW_SEEK_END);
253+
break;
230254
}
231255
} while ( ch != 12 );
232256

233-
for(i = 0; i < 256; i++) {
257+
for ( i = 0; i < 256; i++ ) {
234258
SDL_RWread(src, &colors[i].r, 1, 1);
235259
SDL_RWread(src, &colors[i].g, 1, 1);
236260
SDL_RWread(src, &colors[i].b, 1, 1);
237261
}
238262
} else {
239-
for(i = 0; i < nc; i++) {
263+
for ( i = 0; i < nc; i++ ) {
240264
colors[i].r = pcxh.Colormap[i * 3];
241265
colors[i].g = pcxh.Colormap[i * 3 + 1];
242266
colors[i].b = pcxh.Colormap[i * 3 + 2];

0 commit comments

Comments
 (0)