CodeQL queries 1.24

Skip to end of metadata
Go to start of metadata

Name: User-controlled data in arithmetic expression

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

ID: java/tainted-arithmetic

Kind: path-problem

Severity: warning

Precision: medium

Query: ArithmeticTainted.ql
/**
 * @name User-controlled data in arithmetic expression
 * @description Arithmetic operations on user-controlled data that is not validated can cause
 *              overflows.
 * @kind path-problem
 * @problem.severity warning
 * @precision medium
 * @id java/tainted-arithmetic
 * @tags security
 *       external/cwe/cwe-190
 *       external/cwe/cwe-191
 */

import java
import semmle.code.java.dataflow.FlowSources
import ArithmeticCommon
import DataFlow::PathGraph

class RemoteUserInputOverflowConfig extends TaintTracking::Configuration {
  RemoteUserInputOverflowConfig() { this = "ArithmeticTainted.ql:RemoteUserInputOverflowConfig" }

  override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

  override predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }

  override predicate isSanitizer(DataFlow::Node n) { overflowBarrier(n) }
}

class RemoteUserInputUnderflowConfig extends TaintTracking::Configuration {
  RemoteUserInputUnderflowConfig() { this = "ArithmeticTainted.ql:RemoteUserInputUnderflowConfig" }

  override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }

  override predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }

  override predicate isSanitizer(DataFlow::Node n) { underflowBarrier(n) }
}

from DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, string effect
where
  any(RemoteUserInputOverflowConfig c).hasFlowPath(source, sink) and
  overflowSink(exp, sink.getNode().asExpr()) and
  effect = "overflow"
  or
  any(RemoteUserInputUnderflowConfig c).hasFlowPath(source, sink) and
  underflowSink(exp, sink.getNode().asExpr()) and
  effect = "underflow"
select exp, source, sink,
  "$@ flows to here and is used in arithmetic, potentially causing an " + effect + ".",
  source.getNode(), "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:

  • Validate the user input.
  • Define a guard on the arithmetic expression, so that the operation is performed only if the result can be known to be less than, or equal to, the maximum value for the type, for example MAX_VALUE.
  • Use a wider type, so that larger input values do not cause overflow.
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.

class Test {
	public static void main(String[] args) {
		{
			int data;

			BufferedReader readerBuffered = new BufferedReader(
					new InputStreamReader(System.in, "UTF-8"));
			String stringNumber = readerBuffered.readLine();
			if (stringNumber != null) {
				data = Integer.parseInt(stringNumber.trim());
			} else {
				data = 0;
			}

			// BAD: may overflow if input data is very large, for example
			// 'Integer.MAX_VALUE'
			int scaled = data * 10;

			//...
			
			// GOOD: use a guard to ensure no overflows occur
			int scaled2;
			if (data < Integer.MAX_VALUE / 10)
				scaled2 = data * 10;
			else
				scaled2 = Integer.MAX_VALUE;
		}
	}
}

References