0

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

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 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 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 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 at 8:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.