bug-gnulib
[Top][All Lists]
Advanced

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

[PATCH 3/3] fts: fix race + mishandling of fstatat failure


From: Paul Eggert
Subject: [PATCH 3/3] fts: fix race + mishandling of fstatat failure
Date: Tue, 6 Dec 2022 10:43:59 -0800

I hope this fixes a Luke Dashjr coreutils bug report about ext4
ramdisks; see “9.1: du Aborted (corrupt filesystem)”
<https://debbugs.gnu.org/59821>.
* lib/fts.c (fts_build): Fix two bugs.  First, fts_stat was being
called without checking its return value, causing a later abort.
Second, there was a race between opening a directory and statting
it, fixed by using fstat on the file descriptor rather than
fstatat on the directory name.
---
 ChangeLog | 10 ++++++++++
 lib/fts.c | 32 ++++++++++++++++++++++++--------
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 54e3a23457..feab2d6ca4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2022-12-06  Paul Eggert  <eggert@cs.ucla.edu>
 
+       fts: fix race + mishandling of fstatat failure
+       I hope this fixes a Luke Dashjr coreutils bug report about ext4
+       ramdisks; see “9.1: du Aborted (corrupt filesystem)”
+       <https://debbugs.gnu.org/59821>.
+       * lib/fts.c (fts_build): Fix two bugs.  First, fts_stat was being
+       called without checking its return value, causing a later abort.
+       Second, there was a race between opening a directory and statting
+       it, fixed by using fstat on the file descriptor rather than
+       fstatat on the directory name.
+
        fts: omit goto break_without_closedir
        * lib/fts.c (fts_build): Refactor to omit goto.
 
diff --git a/lib/fts.c b/lib/fts.c
index 27354d39c8..74a08f7ec8 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -1316,19 +1316,35 @@ fts_build (register FTS *sp, int type)
             /* Rather than calling fts_stat for each and every entry 
encountered
                in the readdir loop (below), stat each directory only right 
after
                opening it.  */
-            if (cur->fts_info == FTS_NSOK)
-              cur->fts_info = fts_stat(sp, cur, false);
-            else if (sp->fts_options & FTS_TIGHT_CYCLE_CHECK)
-              {
-                /* Now read the stat info again after opening a directory to
+            bool stat_optimization = cur->fts_info == FTS_NSOK;
+
+            if (stat_optimization
+                /* Also read the stat info again after opening a directory to
                    reveal eventual changes caused by a submount triggered by
                    the traversal.  But do it only for utilities which use
                    FTS_TIGHT_CYCLE_CHECK.  Therefore, only find and du
                    benefit/suffer from this feature for now.  */
-                LEAVE_DIR (sp, cur, "4");
-                fts_stat (sp, cur, false);
-                if (! enter_dir (sp, cur))
+                || ISSET (FTS_TIGHT_CYCLE_CHECK))
+              {
+                if (!stat_optimization)
+                  LEAVE_DIR (sp, cur, "4");
+                if (fstat (dir_fd, cur->fts_statp) != 0)
+                  {
+                    int fstat_errno = errno;
+                    closedir_and_clear (cur->fts_dirp);
+                    if (type == BREAD)
+                      {
+                        cur->fts_errno = fstat_errno;
+                        cur->fts_info = FTS_NS;
+                      }
+                    __set_errno (fstat_errno);
+                    return NULL;
+                  }
+                if (stat_optimization)
+                  cur->fts_info = FTS_D;
+                else if (! enter_dir (sp, cur))
                   {
+                    closedir_and_clear (cur->fts_dirp);
                     __set_errno (ENOMEM);
                     return NULL;
                   }
-- 
2.38.1




reply via email to

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