29

I would like to be able to extract a tar file, such that all extracted files are placed under a certain prefix directory. Any attempt by the tar files to write to outside directories should cause the extraction to fail.

As you might imagine, this is so that I can securely extract an untrusted tar file.

How can I do this with GNU tar?

I came up with:

tar --exclude='/*' --exclude='*/../*' --exclude='../*' -xvf untrusted_file.tar

but I am not sure that this is paranoid enough.

  • 2
    It's not paranoid enough. I constructed some nasty tarballs in the past that ascended via symbolic links that it created. I ended up making my own tar that was setuid-root so it could execute chroot(".") and drop privileges. – Joshua Apr 17 '16 at 3:14
  • 8
    @Joshua so your solution to make a very widely-tested utility more secure was to make your own version and give it root privileges? – OrangeDog Apr 17 '16 at 9:03
  • 4
    @OrangeDog: int main(int argc, char **argv){chroot(".") || exit(1); setuid(getuid()); is easy to audit. – Joshua Apr 17 '16 at 15:10
  • 2
    You might also want to inspect what's inside the tar file by using the -t option. – Thomas Apr 17 '16 at 16:43
38

You don't need the paranoia at all. GNU tar — and in fact any well-written tar program produced in the past 30 years or so — will refuse to extract files in the tarball that begin with a slash or that contain .. elements, by default.

You have to go out of your way to force modern tar programs to extract such potentially-malicious tarballs: both GNU and BSD tar need the -P option to make them disable this protection. See the section Absolute File Names in the GNU tar manual.

The -P flag isn't specified by POSIX,¹ though, so other tar programs may have different ways of coping with this. For example, the Schily Tools' star program uses -/ and -.. to disable these protections.

The only thing you might consider adding to a naïve tar command is a -C flag to force it to extract things in a safe temporary directory, so you don't have to cd there first.


Asides:

  1. Technically, tar isn't specified by POSIX any more at all. They tried to tell the Unix computing world that we should be using pax now instead of tar and cpio, but the computing world largely ignored them.

    It's relevant here to note that the POSIX specification for pax doesn't say how it should handle leading slashes or embedded .. elements. There's a nonstandard --insecure flag for BSD pax to suppress protections against embedded .. path elements, but there is apparently no default protection against leading slashes; the BSD pax man page indirectly recommends writing -s substitution rules to deal with the absolute path risk.

    That's the sort of thing that happens when a de facto standard remains in active use while the de jure standard is largely ignored.

  • 7
    pax - portable archive interchange Awww, how cute, POSIX thinking it's gonna replace possibly the most widely used archive format :P – cat Apr 17 '16 at 12:02
  • 1
    @cat The default archive format is a reasonably widely supported tar variant (AIUI it's also supposed to support cpio format). Pax is rather an attempt to replace the command interface for dealing with such archives, since tar's command argument handling is... quirky. – Random832 Apr 18 '16 at 2:17
  • Random side note: I'm pretty sure it's "de jour", i.e. the French word, as opposed to "de jure." – Nic Hartley Apr 18 '16 at 4:40
  • 7
    @QPaysTaxes it's not. de jure is Latin and contrasts with the current situation, i.e. what is de facto. De jour should also be du jour to obey French grammar rules. – Prime Apr 18 '16 at 6:23
  • 1
    This is a case of an unfortunate false cognate. The French "du jour" ("of the day") looks/sounds a lot like Latin "de jure" ("of law") here contrasted against "de facto" ("of fact"). One could argue that pax is the "standard of the month" or "standard du jour" to make fun of how new standards are proposed so often, while the vast body of users simply stays with what works for them (de facto standard), knowing that (metaphorically) there will be a new standard tomorrow for them to ignore. – Monty Harder Apr 18 '16 at 14:59
18

With GNU tar, it's simply

tar -xvf untrusted_file.tar

in an empty directory. GNU tar automatically strips a leading / member names when extracting, unless explicitly not told otherwise with the --absolute-names option. GNU tar also detects when the use of ../ would cause a file to be extracted outside of the toplevel directory and puts those files in the toplevel directory instead, e.g. a component foo/../../bar/qux will be extracted as bar/qux in the toplevel directory rather than bar/qux in the parent of the toplevel directory. GNU tar also takes care of symbolic links pointing outside the toplevel directory, e.g. foo -> ../.. and foo/bar will not cause bar to be extracted outside the toplevel directory.

Note that this only applies to (sufficiently recent versions of) GNU tar (as well as some other implementations, e.g. *BSD tar and BusyBox tar). Some other implementations have no such protection.

Because of symbolic links, the protections you use wouldn't be enough: the archive could contain a symbolic link pointing to a directory outside the tree and extract files in that directory. There's no way to solve that problem based purely on the member names, you need to examine the target of symbolic links.

Note that if you're extracting into a directory that already contains symbolic links, the guarantee may no longer hold.

6

To cover a few points the other answers haven't:

  1. First, look what's in the file before you extract it:

    tar -tvf untrusted_tar_file.tar
    

    If there's anything in there you don't trust or want to extract, don't extract the tarball.

  2. Second, extract the tarball as a non-root user that only has write access to the one directory you're extracting the tarball into. For example, extract the tarball from within the non-root user's home directory.
  • 4
    1. That is not practical for batch operations. 2. Unless you're running a custom setup, certain locations can be written to by all users, notably /tmp/ – pipe Apr 17 '16 at 7:20
  • @pipe one could also make a directory and a new user, and only that user has access to only that directory, then run the command. I quite like my home directory, thank you. – cat Apr 17 '16 at 12:05
  • 2
    @pipe Why on God's good Earth would you EVER pass untrusted data through a batch operation? If you don't trust it, you DON'T run it unattended. – Andrew Henle Apr 17 '16 at 12:44
  • 6
    @AndrewHenle Uhm, ok. How do you think every server on the internet works? Do you think some guy at stackexchange runs this comment through their database and markup system while manually monitoring the operation? Because this input is untrusted data through a batch operation. – pipe Apr 17 '16 at 22:43

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.