Semmle 1.20
Skip to end of metadata
Go to start of metadata

Name: Overflow in uncontrolled allocation size

Description: Allocating memory with a size controlled by an external user can result in integer overflow.

ID: cpp/uncontrolled-allocation-size

Kind: problem

Severity: error

Precision: high

Query: TaintedAllocationSize.ql
/**
 * @name Overflow in uncontrolled allocation size
 * @description Allocating memory with a size controlled by an external
 *              user can result in integer overflow.
 * @kind problem
 * @problem.severity error
 * @precision high
 * @id cpp/uncontrolled-allocation-size
 * @tags reliability
 *       security
 *       external/cwe/cwe-190
 */

import cpp
import semmle.code.cpp.security.TaintTracking

from Expr source, Expr tainted, BinaryArithmeticOperation oper,
     SizeofOperator sizeof, string taintCause
where tainted(source, tainted)
  and oper.getAnOperand() = tainted
  and oper.getOperator() = "*"
  and oper.getAnOperand() = sizeof
  and oper != tainted
  and sizeof.getValue().toInt() > 1
  and isUserInput(source, taintCause)
select
  oper, "This allocation size is derived from $@ and might overflow",
  source, "user input (" + taintCause + ")"

This code calculates an allocation size by multiplying a user input by a sizeof expression. Since the user input has no apparent guard on its magnitude, this multiplication can overflow. When an integer multiply overflows in C, the result can wrap around and be much smaller than intended. A later attempt to put data into the allocated buffer can then overflow.

Recommendation

Guard all integer parameters that come from an external user. Implement a guard with the expected range for the parameter and make sure that the input value meets both the minimum and maximum requirements for this range. If the input value fails this guard then reject the request before proceeding further. If the input value passes the guard then subsequent calculations should not overflow.

Example

int factor = atoi(getenv("BRANCHING_FACTOR"));

// GOOD: Prevent overflow by checking the input
if (factor < 0 || factor > 1000) {
    log("Factor out of range (%d)\n", factor);
    return -1;
}

// This line can allocate too little memory if factor
// is very large.
char **root_node = (char **) malloc(factor * sizeof(char *));

This code shows one way to guard that an input value is within the expected range. If factor fails the guard, then an error is returned, and the value is not used as an argument to the subsequent call to malloc. Without this guard, the allocated buffer might be too small to hold the data intended for it.

References