Add length checking to prevent malicious mdr files to overflow buffers.

This commit is contained in:
Thilo Schulz 2008-04-08 18:56:03 +00:00
parent a9f03d2c19
commit 32bd0ab5bd

View file

@ -404,13 +404,13 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_
} }
#ifdef RAVENMD4
/* /*
================= =================
R_LoadMDR R_LoadMDR
================= =================
*/ */
#ifdef RAVENMD4
static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name ) static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char *mod_name )
{ {
int i, j, k, l; int i, j, k, l;
@ -444,9 +444,9 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
mod->type = MOD_MDR; mod->type = MOD_MDR;
pinmodel->numFrames = LittleLong(pinmodel->numFrames); LL(pinmodel->numFrames);
pinmodel->numBones = LittleLong(pinmodel->numBones); LL(pinmodel->numBones);
pinmodel->ofsFrames = LittleLong(pinmodel->ofsFrames); LL(pinmodel->ofsFrames);
// This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame // This is a model that uses some type of compressed Bones. We don't want to uncompress every bone for each rendered frame
// over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4. // over and over again, we'll uncompress it in this function already, so we must adjust the size of the target md4.
@ -458,6 +458,14 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t))); size += pinmodel->numFrames * pinmodel->numBones * ((sizeof(mdrBone_t) - sizeof(mdrCompBone_t)));
} }
// simple bounds check
if(pinmodel->numBones < 0 ||
sizeof(*mdr) + pinmodel->numFrames * (sizeof(*frame) + (pinmodel->numBones - 1) * sizeof(*frame->bones)) > size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
mod->dataSize += size; mod->dataSize += size;
mod->md4 = mdr = ri.Hunk_Alloc( size, h_low ); mod->md4 = mdr = ri.Hunk_Alloc( size, h_low );
@ -470,7 +478,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
mdr->numBones = pinmodel->numBones; mdr->numBones = pinmodel->numBones;
mdr->numLODs = LittleLong(pinmodel->numLODs); mdr->numLODs = LittleLong(pinmodel->numLODs);
mdr->numTags = LittleLong(pinmodel->numTags); mdr->numTags = LittleLong(pinmodel->numTags);
// We don't care about offset values, we'll generate them ourselves while loading. // We don't care about the other offset values, we'll generate them ourselves while loading.
mod->numLods = mdr->numLODs; mod->numLods = mdr->numLODs;
@ -565,6 +573,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
// swap all the LOD's // swap all the LOD's
for ( l = 0 ; l < mdr->numLODs ; l++) for ( l = 0 ; l < mdr->numLODs ; l++)
{ {
// simple bounds check
if((byte *) (lod + 1) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
lod->numSurfaces = LittleLong(curlod->numSurfaces); lod->numSurfaces = LittleLong(curlod->numSurfaces);
// swap all the surfaces // swap all the surfaces
@ -572,7 +587,15 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod); lod->ofsSurfaces = (int)((byte *) surf - (byte *) lod);
cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces)); cursurf = (mdrSurface_t *) ((byte *)curlod + LittleLong(curlod->ofsSurfaces));
for ( i = 0 ; i < lod->numSurfaces ; i++) { for ( i = 0 ; i < lod->numSurfaces ; i++)
{
// simple bounds check
if((byte *) (surf + 1) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
// first do some copying stuff // first do some copying stuff
surf->ident = SF_MDR; surf->ident = SF_MDR;
@ -616,6 +639,15 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
for(j = 0; j < surf->numVerts; j++) for(j = 0; j < surf->numVerts; j++)
{ {
LL(curv->numWeights);
// simple bounds check
if(curv->numWeights < 0 || (byte *) (v + 1) + (curv->numWeights - 1) * sizeof(*weight) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
v->normal[0] = LittleFloat(curv->normal[0]); v->normal[0] = LittleFloat(curv->normal[0]);
v->normal[1] = LittleFloat(curv->normal[1]); v->normal[1] = LittleFloat(curv->normal[1]);
v->normal[2] = LittleFloat(curv->normal[2]); v->normal[2] = LittleFloat(curv->normal[2]);
@ -623,7 +655,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
v->texCoords[0] = LittleFloat(curv->texCoords[0]); v->texCoords[0] = LittleFloat(curv->texCoords[0]);
v->texCoords[1] = LittleFloat(curv->texCoords[1]); v->texCoords[1] = LittleFloat(curv->texCoords[1]);
v->numWeights = LittleLong(curv->numWeights); v->numWeights = curv->numWeights;
weight = &v->weights[0]; weight = &v->weights[0];
curweight = &curv->weights[0]; curweight = &curv->weights[0];
@ -650,6 +682,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
surf->ofsTriangles = (int)((byte *) tri - (byte *) surf); surf->ofsTriangles = (int)((byte *) tri - (byte *) surf);
curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles)); curtri = (mdrTriangle_t *)((byte *) cursurf + LittleLong(cursurf->ofsTriangles));
// simple bounds check
if(surf->numTriangles < 0 || (byte *) (tri + surf->numTriangles) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
for(j = 0; j < surf->numTriangles; j++) for(j = 0; j < surf->numTriangles; j++)
{ {
tri->indexes[0] = LittleLong(curtri->indexes[0]); tri->indexes[0] = LittleLong(curtri->indexes[0]);
@ -681,6 +720,13 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
mdr->ofsTags = (int)((byte *) tag - (byte *) mdr); mdr->ofsTags = (int)((byte *) tag - (byte *) mdr);
curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags)); curtag = (mdrTag_t *) ((byte *)pinmodel + LittleLong(pinmodel->ofsTags));
// simple bounds check
if(mdr->numTags < 0 || (byte *) (tag + mdr->numTags) > (byte *) mdr + size)
{
ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has broken structure.\n", mod_name);
return qfalse;
}
for (i = 0 ; i < mdr->numTags ; i++) for (i = 0 ; i < mdr->numTags ; i++)
{ {
tag->boneIndex = LittleLong(curtag->boneIndex); tag->boneIndex = LittleLong(curtag->boneIndex);
@ -690,7 +736,7 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char
curtag++; curtag++;
} }
// And finally we know the offset to the end. // And finally we know the real offset to the end.
mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr); mdr->ofsEnd = (int)((byte *) tag - (byte *) mdr);
// phew! we're done. // phew! we're done.