You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 39 Next »

Pointer arithmetic is appropriate only when the pointer argument refers to an array (see ARR37-C. Do not add or subtract an integer to a pointer to a non-array object), including an array of bytes. When performing pointer arithmetic, the size of the value to add to or subtract from a pointer is automatically scaled to the size of the type of the referenced array object. Adding or subtracting a scaled integer value to or from a pointer is insecure because it may result in a pointer that does not point to an element within or one past the end of the array. This is contraindicated by ARR30-C. Do not form or use out of bounds pointers or array subscripts.

Violations of this guideline are indicated when a pointer to an array is added to the result of the sizeof operator or offsetof macro, which return a size and offset, respectively. However, adding an array pointer to the number of array elements, for example, by using the arr[sizeof(arr)/sizeof(arr[0])]) idiom, is allowed provided that arr refers to an array and not a pointer.

Noncompliant Code Example

In this noncompliant code example, sizeof(buf) is added to the array buf. This example is noncompliant because sizeof(buf) is scaled by int and is scaled again when added to buf.

enum { INTBUFSIZE = 80 };

extern int getdata(void);
int buf[INTBUFSIZE];
 
void func(void) {
  int *buf_ptr = buf;

  while (buf_ptr < (buf + sizeof(buf))) {
    *buf_ptr++ = getdata();
  }
}

Compliant Solution

This compliant solution uses an unscaled integer to obtain a pointer to the end of the array:

enum { INTBUFSIZE = 80 };

extern int getdata(void);
int buf[INTBUFSIZE];

void func(void) {
  int *buf_ptr = buf;

  while (buf_ptr < (buf + INTBUFSIZE)) {
    *buf_ptr++ = getdata();
  }
}

Noncompliant Code Example

In this noncompliant code example, skip is added to the pointer s. However, skip represents the byte offset of ull_b in struct big. When added to s, skip is scaled by the size of struct big.

#include <string.h>
#include <stdlib.h>
#include <stddef.h>
 
struct big {
  unsigned long long ull_a;
  unsigned long long ull_b;
  unsigned long long ull_c;
  int si_e;
  int si_f;
};

void func(void) {
  size_t skip = offsetof(struct big, ull_b);
  struct big *s = (struct big *)malloc(sizeof(struct big));
  if (s == NULL) {
    /* Handle malloc error */
  }

  memset(s + skip, 0, sizeof(struct big) - skip);
  /* ... */
  free(s);
  s = NULL;
}

Compliant Solution

The compliant solution uses an unsigned char * to calculate the offset instead of using a struct big *, which would result in scaled arithmetic.

#include <string.h>
#include <stdlib.h>
#include <stddef.h>
 
struct big {
  unsigned long long ull_a;
  unsigned long long ull_b;
  unsigned long long ull_c;
  int si_d;
  int si_e;
};

void func(void) {
  size_t skip = offsetof(struct big, ull_b);
  unsigned char *ptr = (unsigned char *)malloc(sizeof(struct big));
  if (ptr == NULL) {
     /* Handle malloc error */
  }

  memset(ptr + skip, 0, sizeof(struct big) - skip);
  /* ... */
  free(ptr);
  ptr = NULL;
}

Noncompliant Code Example

In this noncompliant code example, wcslen(error_msg) * sizeof(wchar_t) bytes are scaled by the size of wchar_t when added to error_msg:

#include <wchar.h>
#include <stdio.h>
 
enum { WCHAR_BUF = 128 };
 
void func(void) {
  wchar_t error_msg[WCHAR_BUF];

  wcscpy(error_msg, L"Error: ");
  fgetws(error_msg + wcslen(error_msg) * sizeof(wchar_t), WCHAR_BUF - 7, stdin);
  /* ... */
}

Compliant Solution

This compliant solution does not scale the length of the string; wcslen() returns the number of characters, and the addition to error_msg is scaled. 

#include <wchar.h>
#include <stdio.h>

enum { WCHAR_BUF = 128 };
void func(void) {
  wchar_t error_msg[WCHAR_BUF];

  wcscpy(error_msg, L"Error: ");
  fgetws(error_msg + wcslen(error_msg), WCHAR_BUF - 7, stdin);
  /* ... */
}

Risk Assessment

Failure to understand and properly use pointer arithmetic can allow an attacker to execute arbitrary code.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

EXP41-C

High

Probable

High

 P6

L2

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

CERT C Secure Coding StandardARR30-C. Do not form or use out of bounds pointers or array subscripts
ARR37-C. Do not add or subtract an integer to a pointer to a non-array object
ISO/IEC TR 24772:2013Pointer Casting and Pointer Type Changes [HFC]
Pointer Arithmetic [RVG]
MISRA C:2012Rule 18.1 (required)
Rule 18.2 (required)
Rule 18.3 (required)
Rule 18.4 (advisory)
MITRE CWECWE 468, Incorrect pointer scaling

Bibliography

[Dowd 06]Chapter 6, "C Language Issues"
[Murenin 07] 

 


 

  • No labels