Game Development Community

InteriorInstance::readLightmaps problem

by James Urquhart · in Torque Game Engine · 12/18/2004 (5:44 am) · 0 replies

There is a slight problem with the function, InteriorInstance::readLightmaps.
For reference, lets take a look at the first bit:

bool InteriorInstance::readLightmaps(GBitmap**** lightmaps)
{
   ...

   // Load resource
   Stream* pStream = ResourceManager->openStream(mInteriorFileName);
   if (pStream == NULL) {
      Con::errorf(ConsoleLogEntry::General, "Unable to load interior: %s", mInteriorFileName);
      return false;
   }

   InteriorResource* pResource = new InteriorResource;
   bool success = pResource->read(*pStream);
   ResourceManager->closeStream(pStream);
   
   ...

The first thing that is odd about this function is that it loads the Interior again, but of course, that is to extract the lightmaps from it (since they are actually cleared by the Interior Lightmap Manager).
However, there is a flaw with this method of extracting the lightmaps; It is using "mInteriorFilename" from the InteriorInstance as the filename for the interior. This could potentially be changed on the client prior to a relight, potentially allowing a person to "cheat" by purposefully swapping the filename for another equivalent interior (that also has the *same* number of lightmaps).

In order to exploit this potential problem, one needs to change the "interiorFile" property of an InteriorInstance to another interior filename, then relight the scene. However, i have not managed to successfully exploit it, as my changes to the "interiorFile" property seem to be being ignored.

Another possible way of exploiting this code would be to signal a third party program to swap around .dif files before one relights the mission. Since there appears to be no CRC checking in this code, there would not be much of a problem.

Since "readLightmaps" is only used in one place, "InteriorLMManager::loadBaseLightmaps", i thought it would be best to move the logic into there, eliminating the need to create a temporary array of bitmap pointers. I also changed it to load the interior stream via passing along the interior's resource object. (NOTE: this still has the potential problem of the previous point)

Replace everything in the function after "InstanceLMInfo * instanceInfo = interiorInfo->mInstances[instanceHandle];" with :
// Load interior via stream and extract lightmaps that way
   Stream *str = ResourceManager->openStream(instanceInfo->mInstance->getResource()->mSourceResource);
   InteriorResource *interiorRes = new InteriorResource();
   interiorRes->read(*str);
   ResourceManager->closeStream(str);

   // Grab and seperate lightmaps from the interior's lightmaps vector
   for(U32 i = 0; i < interiorRes->getNumDetailLevels(); i++)
   {
      Interior * interior = interiorRes->getDetailLevel(i);
      Interior * lmInterior = instanceInfo->mInstance->getDetailLevel(i);
      AssertFatal(interior && lmInterior, "InteriorLMManager::loadBaseLightmaps: invalid detail level in resource");
      AssertFatal(lmInterior->getLMHandle() != LM_HANDLE(-1), "InteriorLMManager::loadBaseLightmaps: interior not added to manager");
      AssertFatal(lmInterior->getLMHandle() < mInteriors.size(), "InteriorLMManager::loadBaseLightmaps: invalid interior");
      
      InteriorLMInfo * interiorInfo = mInteriors[lmInterior->getLMHandle()];
      InstanceLMInfo * baseInstanceInfo = interiorInfo->mInstances[0];

      for(U32 j = 0; j < interiorInfo->mNumLightmaps; j++)
      {
         GBitmap *bmp = interior->mLightmaps[j]; 
         if (baseInstanceInfo->mLightmapHandles[j])
         {
            TextureObject * texObj = *baseInstanceInfo->mLightmapHandles[j];
            texObj->bitmap = bmp;
         }
         else
            baseInstanceInfo->mLightmapHandles[j] = new TextureHandle(getTextureName(lmInterior, 0, j), bmp, BitmapNoDownloadTexture);
         // Clear out references to this bitmap
         interior->mLightmaps[j] = NULL;
      }
      interior->mLightmaps.clear();
   }

   delete interiorRes;
   return(true);