The readlink() function reads where a link points to. It is unusual, as 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[256]; ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf)); buf[len] = '\0';
A simple (but incorrect) solution to this problem is to try to make buf
large enough that it can always hold the result:
char buf[PATH_MAX+1]; ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf)); buf[len] = '\0';
This "fix" incorrectly assumes that PATH_MAX
represents the longest possible path for a file in the filesystem. (PATH_MAX
only bounds the longest possible relative path that can be passed to the kernel in a single call.) On most Unix and Linux systems, there is no easily-determined maximum length for a file path, and so the off-by-one buffer overflow risk is still present.
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.
char buf[256]; ssizet_t len; if ((len = readlink("/usr/bin/perl", buf, sizeof(buf)-1)) != -1) buf[len] = '\0'; else { /* handle error condition */ }
Risk Analysis
This is a fairly easy mistake to make. Fortunately the consequences are not that harsh, most likely resulting in abnormal program termination.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
POS30-C |
1 (low) |
2 (probable) |
2 (medium) |
P4 |
L3 |
References
[[ilja 06]]
[[Open Group 97]]
[[Open Group 04]]