From a5c3b6cba6b0fe57bfeddc9e0fa56b25736e2eef Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 2 Dec 2020 14:25:42 -0800 Subject: [PATCH] canonicalize: do not assume symlinks have st_ino * lib/canonicalize.c (canonicalize_filename_mode): When checking for loops, use st_dev and st_ino from the parent directory not from the symlink, as pre-2017 POSIX says these members are not reliable for symlinks. Couple this with START (the remaining file name to be resolved), not NAME (the whole file name with START as its suffix). * modules/canonicalize (Depends-on): Depend on stat, not lstat. --- ChangeLog | 9 ++++++++ lib/canonicalize.c | 50 +++++++++++++++++++++++++------------------- modules/canonicalize | 2 +- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 85f2c76a29..81d1c884f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2020-12-02 Paul Eggert + canonicalize: do not assume symlinks have st_ino + * lib/canonicalize.c (canonicalize_filename_mode): + When checking for loops, use st_dev and st_ino from the parent + directory not from the symlink, as pre-2017 POSIX says these + members are not reliable for symlinks. Couple this with START + (the remaining file name to be resolved), not NAME (the whole file + name with START as its suffix). + * modules/canonicalize (Depends-on): Depend on stat, not lstat. + canonicalize: fix EOVERFLOW bug * lib/canonicalize.c (canonicalize_filename_mode): When testing whether a directory entry is a symbolic link, or a diff --git a/lib/canonicalize.c b/lib/canonicalize.c index 7b838e6861..d82ad50430 100644 --- a/lib/canonicalize.c +++ b/lib/canonicalize.c @@ -247,31 +247,39 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) if (buf) { /* A physical traversal and RNAME is a symbolic link. */ - struct stat st; - if (lstat (rname, &st) != 0) - { - saved_errno = errno; - free (buf); - goto error; - } - size_t n, len; - - /* Detect loops. We cannot use the cycle-check module here, - since it's actually possible to encounter the same symlink - more than once in a given traversal. However, encountering - the same symlink,NAME pair twice does indicate a loop. */ - if (seen_triple (&ht, name, &st)) + if (*start) { - if (can_mode == CAN_MISSING) - continue; - saved_errno = ELOOP; - free (buf); - goto error; + /* Get the device and inode of the parent directory, as + pre-2017 POSIX says this info is not reliable for + symlinks. */ + dest[- (end - start)] = '\0'; + struct stat st; + if (stat (*rname ? rname : ".", &st) != 0) + { + saved_errno = errno; + free (buf); + goto error; + } + dest[- (end - start)] = *start; + + /* Detect loops. We cannot use the cycle-check module here, + since it's possible to encounter the same parent + directory more than once in a given traversal. However, + encountering the same (parentdir, START) pair twice does + indicate a loop. */ + if (seen_triple (&ht, start, &st)) + { + if (can_mode == CAN_MISSING) + continue; + saved_errno = ELOOP; + free (buf); + goto error; + } } - n = strlen (buf); - len = strlen (end); + size_t n = strlen (buf); + size_t len = strlen (end); if (!extra_len) { diff --git a/modules/canonicalize b/modules/canonicalize index a48d1930e7..d5eb493117 100644 --- a/modules/canonicalize +++ b/modules/canonicalize @@ -14,10 +14,10 @@ extensions file-set filename hash-triple-simple -lstat memmove nocrash pathmax +stat sys_stat xalloc xgetcwd -- 2.39.5