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 Coding 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; if ((symlink_max = pathconf("/usr/bin/", _PC_SYMLINK_MAX)) == -1 && errno != 0) { /* handle error condition */ } if (symlink_max == -1) bufsize = 10000; else bufsize = symlink_max+1; if ((buf = (char *)malloc(bufsize)) == 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; if ((len = readlink("/usr/bin/perl", buf, sizeof(buf)-1)) != -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 |
1 (low) |
2 (probable) |
2 (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]]
POS01-A. Check for the existence of links 50. POSIX (POS) POS31-C. Do not unlock or destroy another thread's mutex