bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/6] canonicalize: fix EOVERFLOW bug


From: Paul Eggert
Subject: [PATCH 2/6] canonicalize: fix EOVERFLOW bug
Date: Wed, 2 Dec 2020 14:39:42 -0800

* lib/canonicalize.c (canonicalize_filename_mode):
When testing whether a directory entry is a symbolic link, or a
directory or other, do not use lstat or stat or
areadlink_with_size.  Just use areadlink, as this suffices and it
avoids the EOVERFLOW problem that lstat and stat have.
* modules/canonicalize (Depends-on): Depend on areadlink instead
of areadlink-with-size and stat.
---
 ChangeLog            |  9 ++++++
 lib/canonicalize.c   | 67 +++++++++++++++++++-------------------------
 modules/canonicalize |  3 +-
 3 files changed, 39 insertions(+), 40 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 27afc2b4a..85f2c76a2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2020-12-02  Paul Eggert  <eggert@cs.ucla.edu>
 
+       canonicalize: fix EOVERFLOW bug
+       * lib/canonicalize.c (canonicalize_filename_mode):
+       When testing whether a directory entry is a symbolic link, or a
+       directory or other, do not use lstat or stat or
+       areadlink_with_size.  Just use areadlink, as this suffices and it
+       avoids the EOVERFLOW problem that lstat and stat have.
+       * modules/canonicalize (Depends-on): Depend on areadlink instead
+       of areadlink-with-size and stat.
+
        canonicalize-lgpl: fix EOVERFLOW bug
        * lib/canonicalize-lgpl.c: Do not include <sys/stat.h>.
        (__realpath): Do not use lstat.  Just use readlink, as this
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 1fb3878ef..7b838e686 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -206,9 +206,7 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
       for (end = start; *end && !ISSLASH (*end); ++end)
         /* Nothing.  */;
 
-      if (end - start == 0)
-        break;
-      else if (end - start == 1 && start[0] == '.')
+      if (end - start == 1 && start[0] == '.')
         /* nothing */;
       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
         {
@@ -222,8 +220,6 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
         }
       else
         {
-          struct stat st;
-
           if (!ISSLASH (dest[-1]))
             *dest++ = '/';
 
@@ -246,31 +242,19 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
           dest += end - start;
           *dest = '\0';
 
-          if (logical && (can_mode == CAN_MISSING))
-            {
-              /* Avoid the stat in this case as it's inconsequential.
-                 i.e. we're neither resolving symlinks or testing
-                 component existence.  */
-              st.st_mode = 0;
-            }
-          else if ((logical ? stat (rname, &st) : lstat (rname, &st)) != 0)
+          char discard;
+          char *buf = logical ? NULL : areadlink (rname);
+          if (buf)
             {
-              /* FIXME: If errno == EOVERFLOW here, the entry exists.  */
-              saved_errno = errno;
-              if (can_mode == CAN_EXISTING)
-                goto error;
-              if (can_mode == CAN_ALL_BUT_LAST)
+              /* A physical traversal and RNAME is a symbolic link.  */
+              struct stat st;
+              if (lstat (rname, &st) != 0)
                 {
-                  if (end[strspn (end, SLASHES)] || saved_errno != ENOENT)
-                    goto error;
-                  continue;
+                  saved_errno = errno;
+                  free (buf);
+                  goto error;
                 }
-              st.st_mode = 0;
-            }
 
-          if (S_ISLNK (st.st_mode))
-            {
-              char *buf;
               size_t n, len;
 
               /* Detect loops.  We cannot use the cycle-check module here,
@@ -282,15 +266,7 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
                   if (can_mode == CAN_MISSING)
                     continue;
                   saved_errno = ELOOP;
-                  goto error;
-                }
-
-              buf = areadlink_with_size (rname, st.st_size);
-              if (!buf)
-                {
-                  if (can_mode == CAN_MISSING && errno != ENOMEM)
-                    continue;
-                  saved_errno = errno;
+                  free (buf);
                   goto error;
                 }
 
@@ -344,11 +320,26 @@ canonicalize_filename_mode (const char *name, 
canonicalize_mode_t can_mode)
 
               free (buf);
             }
-          else
+          else if (can_mode != CAN_MISSING
+                   && (!logical || readlink (rname, &discard, 1) < 0))
             {
-              if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
+              saved_errno = errno;
+              switch (saved_errno)
                 {
-                  saved_errno = ENOTDIR;
+                case EINVAL:
+                  /* RNAME exists and is not symbolic link.  */
+                  break;
+
+                case ENOENT:
+                  /* RNAME does not exist.  */
+                  if (can_mode == CAN_EXISTING
+                      || (can_mode == CAN_ALL_BUT_LAST
+                          && end[strspn (end, SLASHES)]))
+                    goto error;
+                  break;
+
+                default:
+                  /* Some other problem with RNAME.  */
                   goto error;
                 }
             }
diff --git a/modules/canonicalize b/modules/canonicalize
index 16dfb6999..a48d1930e 100644
--- a/modules/canonicalize
+++ b/modules/canonicalize
@@ -7,7 +7,7 @@ lib/canonicalize.c
 m4/canonicalize.m4
 
 Depends-on:
-areadlink-with-size
+areadlink
 double-slash-root
 errno
 extensions
@@ -18,7 +18,6 @@ lstat
 memmove
 nocrash
 pathmax
-stat
 sys_stat
 xalloc
 xgetcwd
-- 
2.27.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]