CS.SV.TAINTED.CALL.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.CALL.LOOP_BOUND.RESOURCE checker flags code where an unvalidated integer data is passed as a call argument to a function where it is used as a loop boundary while any resource, managed or unmanaged, is allocated within that 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

Copy
  using System;
  using System.IO;
  namespace TaintedResource {
    class TestTaintedResource {
      const string fileName = "File.dat";
  
      public static void TaintedResourceExample1() {
              int num = getTaintedData();
              sinkMethod(num);               // CS.SV.TAINTED.CALL.LOOP_BOUND.RESOURCE
     }
  
     public static void sinkMethod(int value) {
       for(int i = 0; i < value; 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 produces an issue report at line 14, indicating that, “One or more objects are allocated inside a loop body whose exit condition is controlled by an unvalidated integer value 'taintedIntValue' through a call to 'sinkMethod' at line 9.” In this case, potentially tainted data is used as a loop boundary, which could be exploited by a malicious user.

Fixed code example

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;
        }
        sinkMethod(num);
      }
  
      public static void sinkMethod(int value) {
        for(int i = 0; i < value; 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
    {
      ---
      ---
    }
  }

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