On Thu, Jan 29, 2026 at 12:49:06PM -0800, Paul Eggert wrote:
> On 2026-01-29 11:43, Pavel Cahyna wrote:
> > the recent openat2 changes broke --one-top-level with an absolute path as
> > an argument (AFAICS, there is no test for that case).
>
> Also, using an absolute path would appear to contradict the manual, which
> says that the directory must be "beneath the extraction directory (or the
> one passed to '-C')".
Oh, sorry, I missed this part of the manual. Thank you for pointing it
out. So the "bug" was actually improper use that used to be allowed.
> How about if we start by disallowing absolute directories as the argument of
> --one-top-level? That would match the documentation, and would simplify
> whatever other fixes we do. It is not at all clear how an absolute directory
> would fit in with multiple -C options, for example, or whether that would
> even be useful. And it is also not clear how an absolute directory should
> interact with -P.
I agree. What about this?
---------------->8----------------
diff --git a/src/tar.c b/src/tar.c
index 9c53bdbd..f642f5ad 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -2687,6 +2687,11 @@ decode_options (int argc, char **argv)
paxusage (_("Cannot deduce top-level directory name; "
"please set it explicitly with --one-top-level=DIR"));
}
+ if (one_top_level_option)
+ {
+ if (!IS_RELATIVE_FILE_NAME(one_top_level_dir))
+ paxusage (_("Top-level directory name must be a relative path"));
+ }
}
/* If ready to unlink hierarchies, so we are for simpler files. */
---------------->8----------------
> > When
> > using for example --one-top-level=subdir, a tar archive containing
> > target/sensitive can overwrite ./sensitive if there is a preexisting
> > symlink subdir/target -> ../target . I.e. the archive extraction can
> > escape subdir. I think this is unexpected
>
> To fix this, along with some other problems in the neighborhood that you
> didn't go into, I suggest we change how we treat --one-top-level, as
> follows:
>
> 1. We append its DIR argument (or the inferred DIR, if there is no
> option-argument) to any directory specified via '-C'. Without -C we use DIR
> as-is. I.e., with --one-top-level=DIR -C FOO, we open the directory FOO/DIR
> and use that for all extraction; we do not use FOO for extraction. And
> without -C, we open DIR and use that instead of AT_FDCWD.
>
> 2. When we open FOO/DIR (or DIR), we do so via openat2 so that we know that
> DIR does not escape FOO (or escape "." if there is no FOO).
Makes sense.
> 3. If FOO/DIR (or DIR) cannot be opened, we mkdir it, by opening its parent
> directory with openat2 (so that the parent directory does not escape FOO)
> and then using mkdir on that directory. I.e., just one level: we should not
> use the equivalent of mkdir -p.
Do you mean that the argument to --one-top-level (DIR) should not have
multiple components ( no a/b ), or that it could, but only the last
component ( b ) would be created if missing?
> 4. We do (2) and (3) lazily, i.e., only when we need FOO/DIR (or DIR) open
> to extract a file underneath it.
Is it necessary? I would assume that it is simpler to do it
unconditionally at the beginning, and that we need it almost always
anyway.
> 5. Once we've done either (2) or (3) for FOO/DIR, we close the file
> descriptor for FOO because we don't need it any more.
>
> One possible, stricter alternative is to insist on (3) rather than (2).
> I.e., we do not allow --one-top-level to extract over an existing
> subdirectory. This would be more in the spirit of --one-top-level as I
> understand it.
Sure, but it introduces more incompatibility. (I am not using
--one-top-level myself, and I don't know how often it is used and how,
but I see that currently an existing subdirectory is allowed.)
Note also that after the steps above it is still needed to transform the
file names to remove the prefix if they already contain it, to reproduce
the current and documented behavior.
Note also that --one-top-level also affects the output of
--show-transformed, which shows the prefix that gets added. See the
tests onetop04.at and onetop02.at. I think your proposal would affect
that. I suppose this is more for testing and it is worth to sacrifice
compatibility in this case.
Best regards, Pavel