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

Compare with Current View Page History

« Previous Version 29 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.

Non-Compliant Code Example

If len is equal to sizeof(buf), the null terminator will be 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 (errno != 0) {
    /* handle error condition */
}
if (symlink_max == -1) {
    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, and so the off-by-one buffer overflow risk is still present because in between the two calls, the location of /usr/bin/perl could 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 (10000) that it hopes will be sufficient, but there is a small chance that readlink() could 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 example ensures there will be 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 terminate the result of readlink() can result in abnormal program termination.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

POS30-C

low

probable

medium

P4

L3

Related Vulnerabilities

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

References

[[ilja 06]]
[[Open Group 97]]
[[Open Group 04]]


POS02-A. Follow the principle of least privilege      50. POSIX (POS)       POS31-C. Do not unlock or destroy another thread's mutex

  • No labels