The readlink()
function reads where a link points to. It makes no effort to NULLnull-terminate its second argument, buffer
. Instead, it just returns the number of characters it has written.
...
If len
is equal to sizeof(buf)
, the NULL null terminator will be written one byte past the end of buf
.
...
An incorrect solution to this problem is to try to make buf
large enough that it can always hold the result:.
Code Block | ||
---|---|---|
| ||
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.
...