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

Compare with Current View Page History

« Previous Version 85 Next »

Avoid excessive stack allocations, particularly in situations where the growth of the stack can be controlled or influenced by an attacker.

Noncompliant Code Example

The C Standard includes support for variable-length arrays (VLAs). If the array length is derived from an untrusted data source, an attacker can cause the process to perform an excessive allocation on the stack.

This noncompliant code example temporarily stores data read from a source file into a buffer. The buffer is allocated on the stack as a VLA of size bufsize. If bufsize can be controlled by a malicious user, this code can be exploited to cause a denial-of-service attack.

int copy_file(FILE *src, FILE *dst, size_t bufsize) {
  char buf[bufsize];

  while (fgets(buf, bufsize, src)) {
    if (fputs(buf, dst) == EOF) {
      /* Handle error */
    }
  }

  return 0;
}

The BSD extension function alloca() behaves in a similar fashion to VLAs; its use is not recommended [Loosemore 2007].

Compliant Solution

This compliant solution replaces the VLA with a call to malloc(). If malloc() fails, the return value can be checked to prevent the program from terminating abnormally.

int copy_file(FILE *src, FILE *dst, size_t bufsize) {
  if (bufsize == 0) {
    /* Handle error */
  }
  char *buf = (char *)malloc(bufsize);
  if (!buf) {
    return -1;
  }

  while (fgets(buf, bufsize, src)) {
    if (fputs(buf, dst) == EOF) {
      /* Handle error */
    }
  }
  /* ... */
  free(buf);
  return 0;
}

Noncompliant Code Example

Recursion can also lead to large stack allocations. Recursive functions must ensure that they do not exhaust the stack as a result of excessive recursions.

This noncompliant implementation of the Fibonacci function uses recursion.

unsigned long fib1(unsigned int n) {
  if (n == 0) {
    return 0;
  }
  else if (n == 1 || n == 2) {
    return 1;
  }
  else {
    return fib1(n-1) + fib1(n-2);
  }
}

The amount of stack space needed grows exponentially with respect to the parameter n. Large values of n have been shown to cause abnormal program termination.

Compliant Solution

This implementation of the Fibonacci functions eliminates the use of recursion.

unsigned long fib2(unsigned int n) {
  if (n == 0) {
    return 0;
  }
  else if (n == 1 || n == 2) {
    return 1;
  }

  unsigned long prev = 1;
  unsigned long cur = 1;

  unsigned int i;

  for (i = 3; i <= n; i++) {
    unsigned long tmp = cur;
    cur = cur + prev;
    prev = tmp;
  }

  return cur;
}

Because there is no recursion, the amount of stack space needed does not depend on the parameter n, greatly reducing the risk of stack overflow.

Risk Assessment

Program stacks are frequently used for convenient temporary storage because allocated memory is automatically freed when the function returns. Generally, the operating system will grow the stack as needed. However, growing the stack can fail because of a lack of memory or a collision with other allocated areas of the address space (depending on the architecture). When the stack is exhausted, the operating system can terminate the program abnormally. This behavior can be exploited, and an attacker can cause a denial-of-service attack if he or she can control or influence the amount of stack memory allocated.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

MEM05-C

low

likely

medium

P6

L2

Automated Detection

Tool

Version

Checker

Description

Coverity

2017.07

STACK_USE

Can help detect single stack allocations that are dangerously large, although it will not detect excessive stack use resulting from recursion.

PRQA QA-C
Unable to render {include} The included page could not be found.

1520
3670

Partially implemented.

Related Vulnerabilities

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

Related Guidelines

Bibliography

 

  • No labels