CodeQL documentation

Unvalidated local pointer arithmetic

ID: cs/unvalidated-local-pointer-arithmetic
Kind: problem
Severity: warning
Precision: high
Tags:
   - security
   - external/cwe/cwe-119
   - external/cwe/cwe-120
   - external/cwe/cwe-122
   - external/cwe/cwe-788
Query suites:
   - csharp-code-scanning.qls
   - csharp-security-extended.qls
   - csharp-security-and-quality.qls

Click to see the query in the CodeQL repository

It is dangerous to use the result of a virtual method call in pointer arithmetic without validation if external users can provide their own implementation of the virtual method. For example, if the analyzed project is distributed as a library or framework, then the end-user could provide a new implementation that returns any value.

Recommendation

Always validate the result of virtual methods calls before performing pointer arithmetic to avoid reading or writing outside the bounds of an allocated buffer.

Example

In this example, we write to a given element of an array, using an instance of the PossiblyOverridableClass to determine which element to write to.

In the first case, the GetElementNumber method is called, and the result is used in pointer arithmetic without any validation. If the user can define a subtype of PossiblyOverridableClass, they can create an implementation of GetElementNumber that returns an invalid element number. This would lead to a write occurring outside the bounds of the charArray.

In the second case, the result of GetElementNumber is stored, and confirmed to be within the bounds of the array. Note that it is not sufficient to check that it is smaller than the length. We must also ensure that it’s greater than zero, to prevent writes to locations before the buffer as well as afterwards.

public class PossiblyOverridable
{
    public virtual int GetElementNumber()
    {
        // By default returns 0, which is safe
        return 0;
    }
}

public class PointerArithmetic
{
    public unsafe void WriteToOffset(PossiblyOverridable possiblyOverridable,
                                     char[] charArray)
    {
        fixed (char* charPointer = charArray)
        {
            // BAD: Unvalidated use of virtual method call result in pointer arithmetic
            char* newCharPointer = charPointer + possiblyOverridable.GetElementNumber();
            *newCharPointer = 'A';
            // GOOD: Check that the number is viable
            int number = possiblyOverridable.GetElementNumber();
            if (number >= 0 && number < charArray.Length)
            {
                char* newCharPointer2 = charPointer + number;
                *newCharPointer = 'A';
            }
        }
    }
}

References