CS.SV.TAINTED.LOOP_BOUND.RESOURCE

Resource allocation in a loop whose exit condition is controlled by tainted data

Whenever input is accepted from the user or the outside environment, it should be validated for type, length, format, and range before it is used. Until properly validated, the data is said to be tainted. The CS.SV.TAINTED family of checkers looks for the use of tainted data in code.

The CS.SV.TAINTED.LOOP_BOUND.RESOURCE checker flags code where an unvalidated argument is used as a loop boundary while any resource, managed or unmanaged, is allocated within the loop.

While some resources might be quickly disposed of with the garbage collector if no references to it remain at the end of the loop body, the timing of such disposal is not guaranteed. Moreover, some allocated resources can have an increased lifespan that can result in excessive resource consumption, potentially leading to the exhaustion of resources and program failure. This behavior can be exploited by the potential attackers when exit conditions from such loops are controlled by the external input.

Vulnerability and risk

When input to code isn't validated properly, an attacker can craft the input in a form that isn't expected by the application. The receipt of unintended input can result in altered control flow, arbitrary resource control, and arbitrary code execution. With this sort of opportunity, an attacker could

  • provide unexpected values and cause a program crash
  • cause excessive resource consumption
  • read confidential data
  • use malicious input to modify data or alter control flow
  • execute arbitrary commands

Vulnerable code example 1

Copy
   using System;
   using System.IO;
   namespace TaintedResource
   {
     class TestTaintedResource
     {
       const string fileName = "File.dat";
   
       public static void TaintedResourceExample1()
      {
              int num = getTaintedData();
        for(int i = 0; i < num; i++)
        {
           Test obj = new Test();     // CS.SV.TAINTED.LOOP_BOUND.RESOURCE
        }
      }
  
      public static int getTaintedData()
      {
        try
        {
          using (BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open)))
          {
            return(br.ReadInt32());
          }
        }
        catch (Exception e)
        {
          Console.WriteLine(e);
        }
      }
    }
    class Test
    {
      ---
      ---
    }
  }

Klocwork reports a CS.SV.TAINTED.LOOP_BOUND.RESOURCE defect a line 14, indicating that "Unvalidated integer 'num' received through a call to 'getTaintedData' at line 11 can be used in a loop condition at line 12. An object of type 'Test' is allocated inside a potentially infinite loop that can cause uncontrolled limited resource consumption". In this case, potentially tainted data is used as a loop boundary, which could be exploited by a malicious user.

Fixed code example 1

Copy
   using System;
   using System.IO;
   namespace TaintedResource
   {
     class TestTaintedResource
     {
       const string fileName = "File.dat";
   
       public static void TaintedResourceExample1()
      {
              int num = getTaintedData();
        if (num > MAX_ALLOCATION_QUOTA_IN_ONE_GO)
        {
           return;
        }
        for(int i = 0; i < num; i++)
        {
           Test obj = new Test();
        }
      }
  
      public static int getTaintedData()
      {
        try
        {
          using (BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open)))
          {
            return(br.ReadInt32());
          }
        }
        catch (Exception e)
        {
          Console.WriteLine(e);
        }
      }
    }
    class Test
    {
      ---
      ---
    }
  }

Klocwork no longer reports a defect, because the integer 'num' is checked at line 12 before it's used as a loop condition.

Vulnerable code example 2

Copy
   using System;
   using System.IO;
   namespace TaintedResource
   {
     class TestTaintedResource
     {
       const string fileName = "File.dat";
   
       public static void TaintedResourceExample1()
      {
              int num = getTaintedData();
        for(int i = 0; i < num; i++)
        {
           Test obj = new { X=1, Y=2, ---};     // CS.SV.TAINTED.LOOP_BOUND.RESOURCE
        }
      }
  
      public static int getTaintedData()
      {
        try
        {
          using (BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open)))
          {
            return(br.ReadInt32());
          }
        }
        catch (Exception e)
        {
          Console.WriteLine(e);
        }
      }
    }
    class Test
    {
      ---
      ---
    }
  }

Klocwork reports a CS.SV.TAINTED.LOOP_BOUND.RESOURCE defect at line 14, indicating that "Unvalidated integer 'num' received through a call to 'getTaintedData' at line 11 can be used in a loop condition at line 12. An object of type '<anonymous type>' is allocated inside a potentially infinite loop that can cause uncontrolled limited resource consumption". In this case, potentially tainted data is used as a loop boundary, which could be exploited by a malicious user.

Fixed code example 2

Copy
   using System;
   using System.IO;
   namespace TaintedResource
   {
     class TestTaintedResource
     {
       const string fileName = "File.dat";
   
       public static void TaintedResourceExample1()
      {
              int num = getTaintedData();
        if (num > MAX_ALLOCATION_QUOTA_IN_ONE_GO)
        {
           return;
        }
        for(int i = 0; i < num; i++)
        {
           Test obj = new { X=1, Y=2, ---};
        }
      }
  
      public static int getTaintedData()
      {
        try
        {
          using (BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open)))
          {
            return(br.ReadInt32());
          }
        }
        catch (Exception e)
        {
          Console.WriteLine(e);
        }
      }
    }
    class Test
    {
      ---
      ---
    }
  }

Klocwork no longer reports a defect because the integer 'num' is checked at line 12 before it is used as a loop exit condition.