On 2026-06-16 14:47, kalfalakh wrote:
GNU tar extracting a member "a/./b" fails with ENOENT.
It is due to a bug in the emulation of openat2(), more
specifically when processing dotlike components,
resulting in openat() being called on "". Please see
the proposed attached patch.

Thanks for reporting the problem. I think I see the cause, and installed the attached patch into Gnulib. Please give the patch a try. If it doesn't fix things for you, please let us know the platform you're running on. Also, it'd be nice to see a test case illustrating the unfixed bug, e.g., in the form of a patch to tests/test-openat2.c.
From 50d7bb88f547aff37e6279bdc84a7602e1dd3533 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 17 Jun 2026 00:19:35 -0700
Subject: [PATCH] openat2: fix bug with trailing "/./"

Problem reported by Kinan Al-Falakh in:
https://lists.gnu.org/r/bug-gnulib/2026-06/msg00070.html
* lib/openat2.c (do_openat2): When opening a dotlike component at
file name end, also set the G and H indexes appropriately for ".".
This matters if the file name ends in something like "/./" so the
last component "." is not at file name end.
* tests/test-openat2.c (do_test_resolve): Test for the bug.
---
 ChangeLog            | 11 +++++++++++
 lib/openat2.c        |  3 ++-
 tests/test-openat2.c | 11 +++++++++++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index ee4fcf6978..845f806fc6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2026-06-17  Paul Eggert  <[email protected]>
+
+	openat2: fix bug with trailing "/./"
+	Problem reported by Kinan Al-Falakh in:
+	https://lists.gnu.org/r/bug-gnulib/2026-06/msg00070.html
+	* lib/openat2.c (do_openat2): When opening a dotlike component at
+	file name end, also set the G and H indexes appropriately for ".".
+	This matters if the file name ends in something like "/./" so the
+	last component "." is not at file name end.
+	* tests/test-openat2.c (do_test_resolve): Test for the bug.
+
 2026-06-16  Paul Eggert  <[email protected]>
 
 	openat2: set HAVE_OPENAT2=0 if openat2 is missing
diff --git a/lib/openat2.c b/lib/openat2.c
index 2be62c921c..8c722427f7 100644
--- a/lib/openat2.c
+++ b/lib/openat2.c
@@ -320,8 +320,9 @@ do_openat2 (int *fd, char const *filename,
             {
               /* This is empty or the last component, and acts like ".".
                  Use "." regardless of whether it was "" or "." or "..".  */
-              f = sizeof ".";
+              f = g = sizeof ".";
               e[-f] = '.';
+              h = 1;
             }
 
           /* Open the current component, as either an internal directory or
diff --git a/tests/test-openat2.c b/tests/test-openat2.c
index 0085410ed9..cde9576fbd 100644
--- a/tests/test-openat2.c
+++ b/tests/test-openat2.c
@@ -514,6 +514,17 @@ do_test_resolve (void)
     ASSERT (errno == EXDEV);
     ASSERT (fd == -1);
 
+    /* Check that RESOLVE_BENEATH works with trailing "/./".  */
+    fd = openat2 (dfd,
+                  "subdir/./",
+                  (&(struct open_how)
+                   {
+                     .flags = O_RDONLY,
+                     .resolve = RESOLVE_BENEATH,
+                   }),
+                  sizeof (struct open_how));
+    ASSERT (close (fd) == 0);
+
     ASSERT (close (subdfd) == 0);
   }
 }
-- 
2.53.0

Reply via email to