Skip to content

Commit 4b56392

Browse files
committed
pcx: backport security and bug fixes from the main 2.0 branch:
TALOS-2019-0841: heap buffer overlow exploit TALOS-2019-0821: reading invalid data from the file when bpl is -1 mainstream commits: https://hg.libsdl.org/SDL_image/rev/7453e79c8cdb https://hg.libsdl.org/SDL_image/rev/b920be2b3fc6 https://hg.libsdl.org/SDL_image/rev/e7e9786a1a34 https://hg.libsdl.org/SDL_image/rev/94e5942b92af
1 parent 239846a commit 4b56392

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

IMG_pcx.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
100100
Uint8 *row, *buf = NULL;
101101
char *error = NULL;
102102
int bits, src_bits;
103+
int count = 0;
104+
Uint8 ch;
103105

104106
if ( !src ) {
105107
/* The error message has been set in SDL_RWFromFile */
@@ -117,6 +119,20 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
117119
pcxh.Ymax = SDL_SwapLE16(pcxh.Ymax);
118120
pcxh.BytesPerLine = SDL_SwapLE16(pcxh.BytesPerLine);
119121

122+
#if 0
123+
printf("Manufacturer = %d\n", pcxh.Manufacturer);
124+
printf("Version = %d\n", pcxh.Version);
125+
printf("Encoding = %d\n", pcxh.Encoding);
126+
printf("BitsPerPixel = %d\n", pcxh.BitsPerPixel);
127+
printf("Xmin = %d, Ymin = %d, Xmax = %d, Ymax = %d\n", pcxh.Xmin, pcxh.Ymin, pcxh.Xmax, pcxh.Ymax);
128+
printf("HDpi = %d, VDpi = %d\n", pcxh.HDpi, pcxh.VDpi);
129+
printf("NPlanes = %d\n", pcxh.NPlanes);
130+
printf("BytesPerLine = %d\n", pcxh.BytesPerLine);
131+
printf("PaletteInfo = %d\n", pcxh.PaletteInfo);
132+
printf("HscreenSize = %d\n", pcxh.HscreenSize);
133+
printf("VscreenSize = %d\n", pcxh.VscreenSize);
134+
#endif
135+
120136
/* Create the surface of the appropriate type */
121137
width = (pcxh.Xmax - pcxh.Xmin) + 1;
122138
height = (pcxh.Ymax - pcxh.Ymin) + 1;
@@ -142,22 +158,22 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
142158
}
143159
surface = SDL_AllocSurface(SDL_SWSURFACE, width, height,
144160
bits, Rmask, Gmask, Bmask, Amask);
145-
if ( surface == NULL )
161+
if ( surface == NULL ) {
146162
goto done;
163+
}
147164

148165
bpl = pcxh.NPlanes * pcxh.BytesPerLine;
149-
if (bpl > surface->pitch) {
150-
error = "bytes per line is too large (corrupt?)";
166+
buf = (Uint8 *)calloc(bpl, 1);
167+
if (!buf) {
168+
error = "Out of memory";
169+
goto done;
151170
}
152-
buf = (Uint8 *)calloc(SDL_max(bpl, surface->pitch), 1);
153171
row = (Uint8 *)surface->pixels;
154172
for ( y=0; y<surface->h; ++y ) {
155173
/* decode a scan line to a temporary buffer first */
156-
int i, count = 0;
157-
Uint8 ch;
158-
Uint8 *dst = (src_bits == 8) ? row : buf;
174+
int i;
159175
if ( pcxh.Encoding == 0 ) {
160-
if(!SDL_RWread(src, dst, bpl, 1)) {
176+
if(!SDL_RWread(src, buf, bpl, 1)) {
161177
error = "file truncated";
162178
goto done;
163179
}
@@ -168,16 +184,17 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
168184
error = "file truncated";
169185
goto done;
170186
}
171-
if( (ch & 0xc0) == 0xc0) {
172-
count = ch & 0x3f;
187+
if (ch < 0xc0) {
188+
count = 1;
189+
} else {
190+
count = ch - 0xc0;
173191
if(!SDL_RWread(src, &ch, 1, 1)) {
174192
error = "file truncated";
175193
goto done;
176194
}
177-
} else
178-
count = 1;
195+
}
179196
}
180-
dst[i] = ch;
197+
buf[i] = ch;
181198
count--;
182199
}
183200
}
@@ -199,14 +216,21 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
199216
}
200217
}
201218
}
219+
} else if(src_bits == 8) {
220+
/* Copy the row directly */
221+
memcpy(row, buf, SDL_min(width, bpl));
202222
} else if(src_bits == 24) {
203223
/* de-interlace planes */
204224
Uint8 *innerSrc = buf;
205225
int plane;
206226
for(plane = 0; plane < pcxh.NPlanes; plane++) {
207227
int x;
208-
dst = row + plane;
228+
Uint8 *dst = row + plane;
209229
for(x = 0; x < width; x++) {
230+
if (dst >= row+surface->pitch) {
231+
error = "decoding out of bounds (corrupt?)";
232+
goto done;
233+
}
210234
*dst = *innerSrc++;
211235
dst += pcxh.NPlanes;
212236
}
@@ -227,8 +251,9 @@ SDL_Surface *IMG_LoadPCX_RW(SDL_RWops *src)
227251
/* look for a 256-colour palette */
228252
do {
229253
if ( !SDL_RWread(src, &ch, 1, 1)) {
230-
error = "file truncated";
231-
goto done;
254+
/* Couldn't find the palette, try the end of the file */
255+
SDL_RWseek(src, -768, RW_SEEK_END);
256+
break;
232257
}
233258
} while ( ch != 12 );
234259

0 commit comments

Comments
 (0)