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

Compare with Current View Page History

« Previous Version 54 Next »

The readlink() function reads where a link points to. It makes no effort to null-terminate its second argument, buffer. Instead, it just returns the number of characters it has written.

Noncompliant Code Example

If len is equal to sizeof(buf), the null terminator is written one byte past the end of buf.

char buf[1024];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf));
buf[len] = '\0';

An incorrect solution to this problem is to try to make buf large enough that it can always hold the result.

long symlink_max;
size_t bufsize;
char *buf;
ssize_t len;

errno = 0;
symlink_max = pathconf("/usr/bin/", _PC_SYMLINK_MAX);
if (symlink_max == -1) {
  if (errno != 0) {
    /* handle error condition */
  }
  bufsize = 10000;
}
else {
  bufsize = symlink_max+1;
}

buf = (char *)malloc(bufsize);
if (buf == NULL) {
  /* handle error condition */
}

len = readlink("/usr/bin/perl", buf, bufsize);
buf[len] = '\0';

This modification incorrectly assumes that the symbolic link cannot be longer than the value of SYMLINK_MAX returned by pathconf(). However, the value returned by pathconf() is out of date by the time readlink() is called, so the off-by-one buffer overflow risk is still present because, in between the two calls, the location of /usr/bin/perl can change to a file system with a larger SYMLINK_MAX value. Also, if SYMLINK_MAX is indeterminate (that is, if pathconf() returned -1 without setting errno), the code uses an arbitrary large buffer size (10,000) that it hopes will be sufficient, but there is a small chance that readlink() can return exactly this size.

An additional issue is that readlink() can return -1 if it fails, causing an off-by-one underflow.

Compliant Solution

This compliant solution ensures there is no overflow by only reading in sizeof(buf)-1 characters. It also properly checks to see if an error has occurred.

enum { BUFFERSIZE = 1024 };
char buf[BUFFERSIZE];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf)-1);

if (len != -1) {
  buf[len] = '\0';
}
else {
  /* handle error condition */
}

Risk Assessment

Failing to properly null-terminate the result of readlink() can result in abnormal program termination and buffer-overflow vulnerabilities.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

POS30-C

high

probable

medium

P12

L1

Automated Detection

Tool

Version

Checker

Description

Compass/ROSE

 

 

 

Related Vulnerabilities

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

Related Guidelines

MITRE CWE: CWE-170, "Improper Null Termination"

Bibliography

[Ilja 2006]
[Open Group 1997a]
[Open Group 2004]


      50. POSIX (POS)      POS33-C. Do not use vfork()

  • No labels