Semmle 1.21
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

predicate taintedAllocSize(Expr e, Expr source, string taintCause) {
    isAllocationExpr(e) or
    any(MulExpr me | me.getAChild() instanceof SizeofOperator) = e
  ) and
  exists(Expr tainted |
    tainted = e.getAChild() and
    tainted.getUnspecifiedType() instanceof IntegralType and
    isUserInput(source, taintCause) and
    tainted(source, tainted)

from Expr e, Expr source, string taintCause
where taintedAllocSize(e, source, taintCause)
select e, "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.


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.


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.