2

While trying to make my tarballs reproducible, i followed this guide.

As a side-effect I noticed that I can easily create a tar-file that, when unpacked will change the permissions of the current working directory (where i extract my files into).

Like so:

$ rm -rf /tmp/user
$ mkdir -p /tmp/user/test
$ touch /tmp/user/test/README.txt

$ ls -lhan /tmp/user/ /tmp/user/test/README.txt 
-rw-r--r-- 1 11002 11002    0 Sep 15 10:31 /tmp/user/test/README.txt
/tmp/user/:
total 32K
drwxr-xr-x  3 11002 11002 4.0K Sep 15 10:31 .
drwxrwxrwt 23     0     0  20K Sep 15 10:31 ..
drwxr-xr-x  2 11002 11002 4.0K Sep 15 10:31 test
$ cd /tmp/user/test
$ tar --numeric-owner --owner=0 --group=0 --mode="go-rwx,u-w" --transform 's|\./|foobar/|' \
      -czf ../foobar.tgz .
$ tar tvf ../foobar.tgz
dr-x------ 0/0               0 2021-09-15 10:25 ./
-r-------- 0/0               0 2021-09-15 10:25 foobar/README.txt
$ cd /tmp/user/
$ tar xvf foobar.tgz
$ ls -lhan
total 40K
dr-x------  4 11002 11002 4.0K Sep 15 10:31 .
drwxrwxrwt 23     0     0  20K Sep 15 10:31 ..
drwxr-xr-x  2 11002 11002 4.0K Sep 15 10:33 foobar
-rw-r--r--  1 11002 11002  143 Sep 15 10:32 foobar.tgz
drwxr-xr-x  2 11002 11002 4.0K Sep 15 10:31 test
$ rm foobar.tgz 
rm: cannot remove 'foobar.tgz': Permission denied
$

So what happens is:

  • the tarfile contains a ./ entry that has permissions 0500 (aka r-x------)
  • when extracting the tarfile it will also extract the ./ direcctory (which happens to be the current directory) and sets its permissions to the ones found in the archive
  • after the operation, the user can no longer remove files from this directory and others can no longer do anything with it.

this comes as a big surprise. it might render the system "unusable" for the user (e.g. effectively running chmod a-rwx on the users home directory).

of course it is easy enough to restore the permissions - if you have heard of chmod before (something the typical Ubuntu user might not) and you remember the prior permissions (something I cannot say for myself and an arbitrary directory where i would extract a tarball)

so my question is twofold:

  • how can i prevent tar --extract to change the permissions of my current working directory while still preserving the permissions of the other files in the archive?
  • how can I prevent tar --create from actually creating such an archive (so that it also works for people that don't know the answer to the first question), while still prepending a known path-component)?

edit

i probably already found parts of the answer to my 2nd question.

Changing the path mangling to --transform 's|^\.|foobar|' will also mangle the ./ entry into foobar/, which will then get the permissions declared in the archive (and leave my current working directory alone). I wonder though why --transform 's|\./|foobar/|' will not mangle ./ (as it seems this matches the \./ regex nicely.

1 Answer 1

1

As far as I’m aware, the only way to prevent changes to .’s metadata when extracting a tarball is to skip existing files, with the --skip-old-files option available in GNU tar. This covers more than . and will result in any existing files being kept as-is, instead of being overwritten by the version in the tarball.

I’m not sure why your --transform fails. The recommended approach to prepend a path when extracting is to “replace” the start anchor with the desired directory, e.g. tar --transform 's,^,foobar/,' .... To avoid messing up symlinks, a suffix can be added, e.g. tar --transform 's,^,foobar/,S' which will not apply the transformation to symlink targets.

4
  • afaict ./ does not match because the entry in the tarfile is really . and flagged as a directory, and it's only the printout of --list that appends the trailing / to indicate that this entry is indeed a directory. the entry ./README.txt does match $./ so it is replaced correctly, whereas the directory itself . (disguised as ./) matches $.^
    – umläute
    Sep 16, 2021 at 8:13
  • @umläute that’s what I thought initially, but the raw contents of the archive do contain ./ in the corresponding entry. Sep 16, 2021 at 8:18
  • another problem that i just stumbled upon is, that the transformation is also applied to symlink targets, so if my archive contains a symlink ./blabla/README.txt -> ../README.txt this will by transformed to foobar/blabla/README.txt -> foobar./README.txt (in my transformation) resp. foobar/./blabla/README.txt -> foobar/../README.txt (in yours) which are both unusable. it seems i really need two transforms: --transform 's|^\./|foobar/|' --transform 's|^\.$|foobar|'; urgh.
    – umläute
    Sep 16, 2021 at 8:18
  • 1
    @umläute the linked documentation explains how to handle symlinks; see the S suffix (so --transform 's,^,foobar/,S'). Sep 16, 2021 at 8:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .