[PATCH] openat2: fix trailing-slash dotlike final component
kalfalakh <[email protected]>
| Newsgroups | gmane.comp.lib.gnulib.bugs |
|---|---|
| Message-ID | <[email protected]> |
Hi all, 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, Kinan
0001-openat2-fix-trailing-slash-dotlike-final-component.patch
(text/x-patch, 2.1 KB)
From 5bb08e9ea80308572779f00a8b41ab2b21b3f658 Mon Sep 17 00:00:00 2001 From: Kinan Al-Falakh <[email protected]> Date: Tue, 16 Jun 2026 23:38:02 +0200 Subject: [PATCH] openat2: fix trailing-slash dotlike final component do_openat2 rewrites a dotlike component to "." before opening it, by setting f to 2 and storing '.' at e[-f]. When such a final component has a trailing slash, h == 2 as well. So that store and the following e[-h] = '\0' terminator hit the same byte: the NUL overwrites the '.', and openat() is given "" and fails with ENOENT. This breaks, e.g. GNU tar extracting a member named "a/./b" on hosts that use the emulation. * lib/openat2.c (do_openat2): Store the dotlike '.' after the e[-h] = '\0' terminator. --- lib/openat2.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/openat2.c b/lib/openat2.c index 2be62c921c..62f5d39791 100644 --- a/lib/openat2.c +++ b/lib/openat2.c @@ -316,13 +316,6 @@ do_openat2 (int *fd, char const *filename, } else { - if (dotlike) - { - /* This is empty or the last component, and acts like ".". - Use "." regardless of whether it was "" or "." or "..". */ - f = sizeof "."; - e[-f] = '.'; - } /* Open the current component, as either an internal directory or the final open. Do not follow symlinks. */ @@ -332,6 +325,20 @@ do_openat2 (int *fd, char const *filename, : flags) | O_NOFOLLOW | (eh ? O_DIRECTORY : 0)); e[-h] = '\0'; + + if (dotlike) + { + /* This is empty or the last component, and acts like ".". + Use "." regardless of whether it was "" or "." or "..". + + Write '.' after the NUL above so that when f == h, the + terminator does not overwrite the '.', which would + make openat() see "". */ + + f = sizeof "."; + e[-f] = '.'; + } + int subfd = openat (*fd, &e[-f], subflags, mode); if (subfd < 0) -- 2.52.0