Add more strict checks for read/write spaces in pcx decode logic

This commit is contained in:
Denis Pauk 2017-10-21 01:01:41 +03:00
parent 61da3dffd1
commit a08374c8cd
2 changed files with 66 additions and 15 deletions

View file

@ -66,7 +66,7 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height)
byte *raw;
pcx_t *pcx;
int x, y;
int len;
int len, full_size;
int dataByte, runLength;
byte *out, *pix;
@ -75,7 +75,7 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height)
/* load the file */
len = FS_LoadFile(filename, (void **)&raw);
if (!raw)
if (!raw || len < sizeof(pcx_t))
{
return;
}
@ -95,7 +95,8 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height)
return;
}
out = Z_Malloc((pcx->ymax + 1) * (pcx->xmax + 1));
full_size = (pcx->ymax + 1) * (pcx->xmax + 1);
out = Z_Malloc(full_size);
*pic = out;
@ -135,7 +136,15 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height)
while (runLength-- > 0)
{
pix[x++] = dataByte;
if ((*pic + full_size) <= (pix + x))
{
x += runLength;
runLength = 0;
}
else
{
pix[x++] = dataByte;
}
}
}
}

View file

@ -122,7 +122,9 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
byte *raw;
pcx_t *pcx;
int x, y;
int len;
int len, full_size;
int pcx_width, pcx_height;
qboolean image_issues = false;
int dataByte, runLength;
byte *out, *pix;
char filename[256];
@ -145,7 +147,7 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
/* load the file */
len = ri.FS_LoadFile(filename, (void **)&raw);
if (!raw)
if (!raw || len < sizeof(pcx_t))
{
R_Printf(PRINT_DEVELOPER, "Bad pcx file %s\n", filename);
return;
@ -165,15 +167,19 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
raw = &pcx->data;
pcx_width = pcx->xmax - pcx->xmin;
pcx_height = pcx->ymax - pcx->ymin;
if ((pcx->manufacturer != 0x0a) || (pcx->version != 5) ||
(pcx->encoding != 1) || (pcx->bits_per_pixel != 8) ||
(pcx->xmax >= 640) || (pcx->ymax >= 480))
(pcx_width >= 4096) || (pcx_height >= 4096))
{
R_Printf(PRINT_ALL, "Bad pcx file %s\n", filename);
return;
}
out = malloc((pcx->ymax + 1) * (pcx->xmax + 1));
full_size = (pcx_height + 1) * (pcx_width + 1);
out = malloc(full_size);
*pic = out;
@ -182,28 +188,49 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
if (palette)
{
*palette = malloc(768);
memcpy(*palette, (byte *)pcx + len - 768, 768);
if (len > 768)
{
memcpy(*palette, (byte *)pcx + len - 768, 768);
}
else
{
image_issues = true;
}
}
if (width)
{
*width = pcx->xmax + 1;
*width = pcx_width + 1;
}
if (height)
{
*height = pcx->ymax + 1;
*height = pcx_height + 1;
}
for (y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1)
for (y = 0; y <= pcx_height; y++, pix += pcx_width + 1)
{
for (x = 0; x <= pcx->xmax; )
for (x = 0; x <= pcx_width; )
{
if (raw - (byte *)pcx > len)
{
// no place for read
image_issues = true;
x = pcx_width;
break;
}
dataByte = *raw++;
if ((dataByte & 0xC0) == 0xC0)
{
runLength = dataByte & 0x3F;
if (raw - (byte *)pcx > len)
{
// no place for read
image_issues = true;
x = pcx_width;
break;
}
dataByte = *raw++;
}
else
@ -213,7 +240,17 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
while (runLength-- > 0)
{
pix[x++] = dataByte;
if ((*pic + full_size) <= (pix + x))
{
// no place for write
image_issues = true;
x += runLength;
runLength = 0;
}
else
{
pix[x++] = dataByte;
}
}
}
}
@ -224,7 +261,7 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
free(*pic);
*pic = NULL;
}
else if(pcx->xmax == 319 && pcx->ymax == 239
else if(pcx_width == 319 && pcx_height == 239
&& Q_strcasecmp(origname, "pics/quit.pcx") == 0
&& Com_BlockChecksum(pcx, len) == 3329419434u)
{
@ -233,6 +270,11 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height)
fixQuitScreen(*pic);
}
if (image_issues)
{
R_Printf(PRINT_ALL, "PCX file %s has possible size issues.\n", filename);
}
ri.FS_FreeFile(pcx);
}