Main Content

CWE Rule 789

Memory Allocation with Excessive Size Value

Since R2023a

Description

Rule Description

The product allocates memory based on an untrusted, large size value, but it does not ensure that the size is within expected limits, allowing arbitrary amounts of memory to be allocated.

Polyspace Implementation

The rule checker checks for these issues:

  • Memory allocation with tainted size

  • Tainted size of variable length array

  • Wrong type used in sizeof

Examples

expand all

Issue

This issue occurs when a memory allocation function, such as calloc or malloc, uses a size argument from an unsecure source.

Risk

Uncontrolled memory allocation can cause your program to request too much system memory. This consequence can lead to a crash due to an out-of-memory condition, or assigning too many resources.

Fix

Before allocating memory, check the value of your arguments to check that they do not exceed the bounds.

Extend Checker

By default, Polyspace® assumes that data from external sources are tainted. See Sources of Tainting in a Polyspace Analysis. To consider any data that does not originate in the current scope of Polyspace analysis as tainted, use the command line option -consider-analysis-perimeter-as-trust-boundary.

Example — Allocate Memory Using Input From User
#include<stdio.h>
#include <stdlib.h>

int* bug_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = (int*)malloc(size);//Noncompliant
    return p;
}

In this example, malloc allocates size bytes of memory for the pointer p. The variable size comes from the user of the program. Its value is not checked, and it could be larger than the amount of available memory. If size is larger than the number of available bytes, your program could crash.

Correction — Check Size of Memory to be Allocated

One possible correction is to check the size of the memory that you want to allocate before performing the malloc operation. This example checks to see if size is positive and less than the maximum size.

#include<stdio.h>
#include <stdlib.h>

enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};

int* corrected_taintedmemoryallocsize(void) {
    size_t size;
    scanf("%zu", &size);
    int* p = NULL;
    if (size>0 && size<SIZE128) {          /* Fix: Check entry range before use */
        p = (int*)malloc((unsigned int)size);
    }
    return p;
}
Issue

This issue occurs when the size of a variable length array (VLA) is obtained from an unsecure source.

Risk

If an attacker changed the size of your VLA to an unexpected value, it can cause your program to crash or behave unexpectedly.

If the size is non-positive, the behavior of the VLA is undefined. Your program does not perform as expected.

If the size is unbounded, the VLA can cause memory exhaustion or stack overflow.

Fix

Validate your VLA size to make sure that it is positive and less than a maximum value.

Extend Checker

By default, Polyspace assumes that data from external sources are tainted. See Sources of Tainting in a Polyspace Analysis. To consider any data that does not originate in the current scope of Polyspace analysis as tainted, use the command line option -consider-analysis-perimeter-as-trust-boundary.

Example — User Input Argument Used as Size of VLA
#include<stdio.h>
#inclule<stdlib.h>
#define LIM 40

long squaredSum(int size) {

	int tabvla[size];  //Noncompliant
	long res = 0;
	for (int i=0 ; i<LIM-1 ; ++i) {
		tabvla[i] = i*i;
		res += tabvla[i];
	}
	return res;
}
int main(){
	int size;
	scanf("%d",&size);
	//...
	long result = squaredSum(size);
	//...
	return 0;
}

In this example, a variable length array size is based on an input argument. Because this input argument value is not checked, the size may be negative or too large.

Correction — Check VLA Size

One possible correction is to check the size variable before creating the variable length array. This example checks if the size is larger than 0 and less than 40, before creating the VLA

#include <stdio.h>
#include <stdlib.h>
#define LIM 40

long squaredSum(int size) {
	long res = 0;
	if (size>0 && size<LIM){
		int tabvla[size];
		for (int i=0 ; i<size || i<LIM-1 ; ++i) {
			tabvla[i] = i*i;
			res += tabvla[i];
		}
	}else{
		res = -1;
	}
	return res;
}
int main(){
	int size;
	scanf("%d",&size);
	//...
	long result = squaredSum(size);
	//...
	return 0;
}
Issue

This issue occurs when both of the following conditions hold:

  1. You assign the address of a block of memory to a pointer, or transfer data between two blocks of memory. The assignment or copy uses the sizeof operator.

    For instance, you initialize a pointer using malloc(sizeof(type)) or copy data between two addresses using memcpy(destination_ptr, source_ptr, sizeof(type)).

  2. You use an incorrect type as argument of the sizeof operator. For instance:

    • You might be using the pointer type instead of the type that the pointer points to. For example, to initialize a type* pointer, you might be using malloc(sizeof(type*)) instead of malloc(sizeof(type)).

    • You might be using a completely unrelated type as sizeof argument. For example, to initialize a type* pointer, you might be using malloc(sizeof(anotherType)).

Risk

Irrespective of what type stands for, the expression sizeof(type*) always returns a fixed size. The size returned is the pointer size on your platform in bytes. The appearance of sizeof(type*) often indicates an unintended usage. The error can cause allocation of a memory block that is much smaller than what you need and lead to weaknesses such as buffer overflows.

For instance, assume that structType is a structure with ten int variables. If you initialize a structType* pointer using malloc(sizeof(structType*)) on a 32-bit platform, the pointer is assigned a memory block of four bytes. However, to be allocated completely for one structType variable, the structType* pointer must point to a memory block of sizeof(structType) = 10 * sizeof(int) bytes. The required size is much greater than the actual allocated size of four bytes.

Fix

To initialize a type* pointer, replace sizeof(type*) in your pointer initialization expression with sizeof(type).

Example — Allocate a Char Array With sizeof
#include <stdlib.h>

void test_case_1(void) {
    char* str;

    str = (char*)malloc(sizeof(char*) * 5);  //Noncompliant
    free(str);

}

In this example, memory is allocated for the character pointer str using a malloc of five char pointers. However, str is a pointer to a character, not a pointer to a character pointer. Therefore the sizeof argument, char*, is incorrect.

Correction — Match Pointer Type to sizeof Argument

One possible correction is to match the argument to the pointer type. In this example, str is a character pointer, therefore the argument must also be a character.

#include <stdlib.h>

void test_case_1(void) {
    char* str;

    str = (char*)malloc(sizeof(char) * 5);
    free(str);

}

Check Information

Category: Others

Version History

Introduced in R2023a