readlink.2: Fix an off-by-one error in example code

An off-by-one error could trigger a buffer overflow in
some cases in the old code.
See https://bugzilla.kernel.org/show_bug.cgi?id=196483

Also some other cosmetic changes to the code (more comments,
better variable names).

Reported-by: Jason Noakes <jjnoakes@gmail.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Michael Kerrisk 2017-08-14 00:03:37 +02:00
parent 928cf4522f
commit f06a3f30fa
1 changed files with 19 additions and 14 deletions

View File

@ -282,8 +282,8 @@ falling back to a buffer of size
in cases where
.BR lstat (2)
reports a size of zero.
.PP
.nf
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
@ -295,8 +295,8 @@ int
main(int argc, char *argv[])
{
struct stat sb;
char *linkname;
ssize_t r, bufsiz;
char *buf;
ssize_t nbytes, bufsiz;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>\\n", argv[0]);
@ -308,37 +308,42 @@ main(int argc, char *argv[])
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 \(aqst_size\(aq as zero. In that case, take PATH_MAX as
a "good enough" estimate */
a "good enough" estimate. */
if (sb.st_size == 0)
bufsiz = PATH_MAX;
printf("%zd\\n", bufsiz);
linkname = malloc(bufsiz);
if (linkname == NULL) {
buf = malloc(bufsiz);
if (buf == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
r = readlink(argv[1], linkname, bufsiz);
if (r == \-1) {
nbytes = readlink(argv[1], buf, bufsiz);
if (nbytes == \-1) {
perror("readlink");
exit(EXIT_FAILURE);
}
linkname[r] = \(aq\\0\(aq;
printf("\(aq%s\(aq points to \(aq%.*s\(aq\\n", argv[1], (int) nbytes, buf);
printf("\(aq%s\(aq points to \(aq%s\(aq\\n", argv[1], linkname);
/* 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 (r == bufsiz)
if (nbytes == bufsiz)
printf("(Returned buffer may have been truncated)\\n");
free(linkname);
free(buf);
exit(EXIT_SUCCESS);
}
.fi