Bug 196483 - readlink(2) example code contains buffer overwrite
Summary: readlink(2) example code contains buffer overwrite
Status: RESOLVED CODE_FIX
Alias: None
Product: Documentation
Classification: Unclassified
Component: man-pages (show other bugs)
Hardware: All Linux
: P1 normal
Assignee: documentation_man-pages@kernel-bugs.osdl.org
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-07-25 18:05 UTC by Jason Noakes
Modified: 2017-08-13 22:01 UTC (History)
2 users (show)

See Also:
Kernel Version:
Subsystem:
Regression: No
Bisected commit-id:


Attachments

Description Jason Noakes 2017-07-25 18:05:05 UTC
The example code in readlink(2) in latest git (a5688441) and online as of when this bug was opened (http://man7.org/linux/man-pages/man2/readlink.2.html) has a bug.

The line that reads "linkname[r] = '\0';" may be writing one byte passed the end of "linkname" in the case where r == bufsiz.
Comment 1 Michael Kerrisk 2017-08-13 22:01:30 UTC
Thanks. I've replaced that code with the code below. If you see any fault in the new code, please reopen this bug.

#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    struct stat sb;
    char *buf;
    ssize_t nbytes, bufsiz;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <pathname>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (lstat(argv[1], &sb) == -1) {
        perror("lstat");
        exit(EXIT_FAILURE);
    }

    /* Add one to the link size, so that we can determine whether
       the buffer returned by readlink() was truncated. */

    bufsiz = sb.st_size + 1;

    /* Some magic symlinks under (for example) /proc and /sys
       report 'st_size' as zero. In that case, take PATH_MAX as
       a "good enough" estimate. */

    if (sb.st_size == 0)
        bufsiz = PATH_MAX;

    buf = malloc(bufsiz);
    if (buf == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    nbytes = readlink(argv[1], buf, bufsiz);
    if (nbytes == -1) {
        perror("readlink");
        exit(EXIT_FAILURE);
    }

    printf("'%s' points to '%.*s'\n", argv[1], (int) nbytes, buf);

    /* If the return value was equal to the buffer size, then the
       the link target was larger than expected (perhaps because the
       target was changed between the call to lstat() and the call to
       readlink()). Warn the user that the returned target may have
       been truncated. */

    if (nbytes == bufsiz)
        printf("(Returned buffer may have been truncated)\n");

    free(buf);
    exit(EXIT_SUCCESS);
}

Note You need to log in before you can comment on or make changes to this bug.