Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: changed the NCCE to use SYMLINK_MAX instead of PATH_MAX

...

Code Block
bgColor#FFcccc
char buf[2561024];
ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf));
buf[len] = '\0';

A simple (but An incorrect ) solution to this problem is to try to make buf large enough that it can always hold the result:

Code Block
bgColor#ffcccc

long symlink_max;
size_t bufsize;
char buf[PATH_MAX+1];
ssize_t *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, sizeof(bufbufsize));
buf[len] = '\0';

This modification 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 paththe 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.

...

Code Block
bgColor#ccccff
enum { BUFFERSIZE = 2561024 };
char buf[BUFFERSIZE];
ssize_t len;

if ((len = readlink("/usr/bin/perl", buf, sizeof(buf)-1)) != -1)
    buf[len] = '\0';
else {
   /* handle error condition */
}

...