Main Content

CWE Rule 124

Buffer Underwrite ('Buffer Underflow')

Since R2023a

Description

Rule Description

The software writes to a buffer using an index or pointer that references a memory location prior to the beginning of the buffer.

Polyspace Implementation

The rule checker checks for these issues:

  • Array access with tainted index

  • Destination buffer underflow in string manipulation

  • Pointer dereference with tainted offset

Examples

expand all

Issue

This issue occurs when you access an array by using an index that is obtained from unsecure sources and which has not been validated.

Risk

The index might be outside the valid array range. If the tainted index is outside the array range, it can cause:

  • Buffer underflow/underwrite — writing to memory before the beginning of the buffer.

  • Buffer overflow — writing to memory after the end of a buffer.

  • Over-reading a buffer — accessing memory after the end of the targeted buffer.

  • Under-reading a buffer, or accessing memory before the beginning of the targeted buffer.

An attacker can use an invalid read or write operation create to problems in your program.

Fix

Before using the index to access the array, validate the index value to make sure that it is inside the array range.

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 — Use Index to Return Buffer Value
#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
  return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
	int num = tainted_int_source();
    return tab[num];//Noncompliant  
}

In this example, the index num accesses the array tab. The index num is obtained from an unsecure source and the function taintedarrayindex does not check to see if num is inside the range of tab.

Correction — Check Range Before Use

One possible correction is to check that num is in range before using it.

#include <stdlib.h>
#include <stdio.h>
#define SIZE100 100
extern int tab[SIZE100];
static int tainted_int_source(void) {
	return strtol(getenv("INDEX"),NULL,10);
}
int taintedarrayindex(void) {
	int num = tainted_int_source();
	if (num >= 0 && num < SIZE100) {
		return tab[num]; 
	} else {
		return -1;
	}
}

Issue

This issue occurs when certain string manipulation functions write to their destination buffer argument at a negative offset from the beginning of the buffer.

For instance, for the function sprintf(char* buffer, const char* format), you obtain the buffer from an operation buffer = (char*)arr; ... buffer += offset;. arr is an array and offset is a negative value.

Risk

Buffer underflow can cause unexpected behavior such as memory corruption or stopping your system. Buffer underflow also introduces the risk of code injection.

Fix

If the destination buffer argument results from pointer arithmetic, see if you are decrementing a pointer. Fix the pointer decrement by modifying either the original value before decrement or the decrement value.

Example — Buffer Underflow in sprintf Use
#include <stdio.h>
#define offset -2

void func(void) {
    char buffer[20];
    char *fmt_string ="Text";

    sprintf(&buffer[offset], fmt_string);  //Noncompliant
}

In this example, &buffer[offset] is at a negative offset from the memory allocated to buffer.

Correction — Change Pointer Decrementer

One possible correction is to change the value of offset.

#include <stdio.h>
#define offset 2

void func(void) {
    char buffer[20];
    char *fmt_string ="Text";

    sprintf(&buffer[offset], fmt_string);     
}
Issue

This issue occurs when a pointer dereference uses an offset variable from an unknown or unsecure source.

This check focuses on dynamically allocated buffers. For static buffer offsets, see Array access with tainted index.

Risk

The index might be outside the valid array range. If the tainted index is outside the array range, it can cause:

  • Buffer underflow/underwrite, or writing to memory before the beginning of the buffer.

  • Buffer overflow, or writing to memory after the end of a buffer.

  • Over reading a buffer, or accessing memory after the end of the targeted buffer.

  • Under-reading a buffer, or accessing memory before the beginning of the targeted buffer.

An attacker can use an invalid read or write to compromise your program.

Fix

Validate the index before you use the variable to access the pointer. Check to make sure that the variable is inside the valid range and does not overflow.

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 — Dereference Pointer Array
#include <stdio.h>
#include <stdlib.h>
enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
extern void read_pint(int*);

int taintedptroffset(void) {
    int offset;
    scanf("%d",&offset);
    int* pint = (int*)calloc(SIZE10, sizeof(int));
    int c = 0;
    if(pint) {
        /* Filling array */
        read_pint(pint);
        c = pint[offset];//Noncompliant
        free(pint);
    }
    return c;
}

In this example, the function initializes an integer pointer pint. The pointer is dereferenced using the input index offset. The value of offset could be outside the pointer range, causing an out-of-range error.

Correction — Check Index Before Dereference

One possible correction is to validate the value of offset. Continue with the pointer dereferencing only if offset is inside the valid range.

#include <stdlib.h>
#include <stdio.h>
enum {
    SIZE10  =  10,
    SIZE100 = 100,
    SIZE128 = 128
};
extern void read_pint(int*);

int taintedptroffset(void) {
    int offset;
    scanf("%d",&offset);
    int* pint = (int*)calloc(SIZE10, sizeof(int));
    int c = 0;
    if (pint) {
        /* Filling array */
        read_pint(pint);
        if (offset>0 && offset<SIZE10) {
            c = pint[offset];
        }
        free(pint);
    }
    return c;
}

Check Information

Category: Memory Buffer Errors

Version History

Introduced in R2023a