Name: User-controlled data in arithmetic expression

Description:

Arithmetic operations on user-controlled data that is not validated can cause overflows.

ID: cpp/tainted-arithmetic

Kind: problem

Severity: warning

Precision: low

/**
 * @name User-controlled data in arithmetic expression
 * @description Arithmetic operations on user-controlled data that is
 *              not validated can cause overflows.
 * @kind problem
 * @problem.severity warning
 * @precision low
 * @id cpp/tainted-arithmetic
 * @tags security
 *       external/cwe/cwe-190
 *       external/cwe/cwe-191
 */
import cpp

import semmle.code.cpp.security.Overflow
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTracking

from Expr origin, Operation op, Expr e, string effect
where isUserInput(origin, _)
  and tainted(origin, e)
  and op.getAnOperand() = e
  and
  (
    (missingGuardAgainstUnderflow(op, e) and effect = "underflow") or
    (missingGuardAgainstOverflow(op, e) and effect = "overflow") or
    (not e instanceof VariableAccess and effect = "overflow")
  ) and (
    op instanceof UnaryArithmeticOperation or
    op instanceof BinaryArithmeticOperation
  )
select e, "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
  origin, "User-provided value"

Performing calculations on user-controlled data can result in integer overflows unless the input is validated.

If the user is free to enter very large numbers, even arithmetic operations that would usually result in a small change in magnitude may result in overflows.

Recommendation

Always guard against overflow in arithmetic operations on user-controlled data by doing one of the following:

Example

In this example, a value is read from standard input into an int. Because the value is a user-controlled value, it could be extremely large. Performing arithmetic operations on this value could therefore cause an overflow. To avoid this happening, the example shows how to perform a check before performing a multiplication.

     1int main(int argc, char** argv) {
     2    char buffer[20];
     3    fgets(buffer, 20, stdin);
     4
     5    int num = atoi(buffer);
     6    // BAD: may overflow if input is very large
     7    int scaled = num + 1000;
     8
     9    // ...
    10
    11    int num2 = atoi(buffer);
    12    int scaled2;
    13    // GOOD: use a guard to prevent overflow
    14    if (num2 < INT_MAX-1000)
    15        scaled2 = num2 + 1000;
    16    else
    17        scaled2 = INT_MAX;
    18}
int main(int argc, char** argv) {
	char buffer[20];
	fgets(buffer, 20, stdin);

	int num = atoi(buffer);
	// BAD: may overflow if input is very large
	int scaled = num + 1000;

	// ...

	int num2 = atoi(buffer);
	int scaled2;
	// GOOD: use a guard to prevent overflow
	if (num2 < INT_MAX-1000)
		scaled2 = num2 + 1000;
	else
		scaled2 = INT_MAX;
}
References