Hello Paul,
On Fri, Jan 30, 2026 at 12:58:28PM -0800, Paul Eggert wrote:
> On 2026-01-30 11:56, Pavel Cahyna wrote:
> > + if (one_top_level_option)
> > + {
> > + if (!IS_RELATIVE_FILE_NAME(one_top_level_dir))
> > + paxusage (_("Top-level directory name must be a relative path"));
> > + }
>
> A good start. I fleshed it out by installing the attached. This also
> clarifies the doc.
>
> By the way, what should '--one-top-level=' (with an empty DIR) do? The
> documentation is unclear. An empty DIR is not a relative file name....
No idea. Shouldn't it be equivalent to just '--one-top-level' ?
> > > 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?
>
> The latter. I am leery of mkdir -p semantics in general, as it has too many
> issues (what permissions should the intermediate directories use?).
Could they use the same permissions as the last one?
> > > 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.
>
> I am worried about combinations like '-C a -C b file', where we should
> create b/DIR (for b/DIR/file) but need not create a/DIR.
Hmm. Is there a a way to know which -C before the extraction starts is
the last one? (Or, when we have processed the last -C before the
extraction starts? And do (2) and (3) at this moment?)
> > > 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.)
>
> Hmm, I see your point but then I am also dubious that such uses are
> advisable.
>
> Come to think of it, how did you discover the openat2 changes vs
> --one-top-level issue? Was it a user bug report? If so, what was the user
> doing?
Yes, user bug report - https://issues.redhat.com/browse/RHEL-143906 .
Here's the code they had to change as a result:
https://github.com/skupperproject/skupper-router/commit/6a9f03f590a1ab44e106b3af63a9fa0f0fbdef30
They remarked that according to a search on GitHub (I had not thought
of that) they are hardly alone. When I search on GitHub for
"--one-top-level", most of the uses are with a relative path, but I saw
some cases with an absolute path.
It seems that the changes to make --one-top-level more secure would be
the same that would be needed to make --one-top-level work with absolute
paths. Is that right? I am thinking that given the current uses, it
could be in fact better to continue supporting absolute paths, even if
it is contrary to the documentation.
> > 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.
>
> I was hoping that we cleverly redo the internals so that none of that stuff
> changes. But you're right, if that's a pain we can sacrifice compatibility;
> I doubt whether anyone will care.
Just to make it clear, I suppose you mean to sacrifice compatibility in
the second case (--show-transformed output) but not in the first
(transformation of file names to remove the prefix if needed), right?
Regarding the patch:
> From 678dbc679a1478da58c884de509ab2844eb04cdb Mon Sep 17 00:00:00 2001
> From: Paul Eggert <[email protected]>
> Date: Fri, 30 Jan 2026 12:48:48 -0800
> Subject: [PATCH] tar: --one-top-level=DIR must be relative
>
> * src/tar.c (decode_options): Require --one-top-level operand
> to be relative.
> ---
> diff --git a/doc/tar.texi b/doc/tar.texi
> index 211b5960..c1b6f7d2 100644
> --- a/doc/tar.texi
> +++ b/doc/tar.texi
> @@ -3274,10 +3274,14 @@ directory.
> @opsummary{one-top-level}
> @item --one-top-level[=@var{dir}]
> Tells @command{tar} to create a new directory beneath the extraction
> directory
> -(or the one passed to @option{-C}) and use it to guard against
> -tarbombs. In the absence of @var{dir} argument, the name of the new
> directory
> -will be equal to the base name of the archive (file name minus the
> -archive suffix, if recognized). Any member names that do not begin
> +(or the one passed to @option{-C}) and use it to prevent @command{tar}
> +from modifying files outside that directory.
> +If @var{dir} is present, it must be a relative file name.
> +If it is absent, the name of the new directory
> +is the base name of the archive minus any recognized archive suffix.
> +If multiple @option{-C} options are present,
> +each has its own subdirectory with the same name.
What does this mean? I tried mkdir -p a/b; tar -C a -C b --one-top-level=foo
-xf ...tgz
and it did not create a/foo and a/b/foo, just a/b/foo.
Do you mean only in the case when the -C options are intermixed with
non-option arguments (paths to extract)? But according to the manual,
this use does not seem to be supported:
'--directory=DIR'
'-C DIR'
When this option is specified, 'tar' will change its current
directory to DIR before performing any operations. When this
option is used during archive creation, it is order sensitive.
Note the "When this option is used during archive creation" - this seems
to imply that you should not use -C in the middle of arguments during
extraction to change directory after some files are extracted, although
in practice this works (is it the same case like --one-top-level with an
absolute path?)
Regards, Pavel