From 64fedc530ea74c5cf6329357f4fdaef5ee8897c6 Mon Sep 17 00:00:00 2001 From: Johannes 'josch' Schauer Date: Tue, 21 Jan 2020 13:24:49 +0100 Subject: [PATCH] Restore deterministic tar with pax and xattr support - all creating and extraction of tarballs respects extended attributes - extended attributes require pax format, so explicitly request the format - to make pax bit-by-bit reproducible, ctime, atime and PID have to be removed from the headers with: --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime - always pass --numeric-owner to tar - always pass --xattrs when creating a tar - always pass --xattrs --xattrs-include=* when extracting a tar --- coverage.sh | 6 +++--- mmdebstrap | 38 +++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/coverage.sh b/coverage.sh index 9e26f9a..745a9ad 100755 --- a/coverage.sh +++ b/coverage.sh @@ -1585,9 +1585,9 @@ echo copy-in-customize > /tmp/copy-in-customize echo tar-in-setup > /tmp/tar-in-setup echo tar-in-essential > /tmp/tar-in-essential echo tar-in-customize > /tmp/tar-in-customize -tar -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup -tar -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential -tar -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize rm /tmp/tar-in-setup rm /tmp/tar-in-essential rm /tmp/tar-in-customize diff --git a/mmdebstrap b/mmdebstrap index 6a9d657..a0330b4 100755 --- a/mmdebstrap +++ b/mmdebstrap @@ -2369,7 +2369,11 @@ sub hookhelper { # path that is valid on the outside -- fakechroot and proot have their # own reasons, see below my @cmdprefix = (); - my @tarcmd = ('tar'); + my @tarcmd = ( + 'tar', '--numeric-owner', '--xattrs', '--format=pax', + '--pax-option=exthdr.name=%d/PaxHeaders/%f,' + . 'delete=atime,delete=ctime' + ); if ($hook eq 'setup') { if ($mode eq 'proot') { # since we cannot run tar inside the chroot under proot during @@ -2378,7 +2382,7 @@ sub hookhelper { # by the user running mmdebstrap. To let the ownership # information not be completely off, we force all files be # owned by the root user. - push @tarcmd, '--owner=root', '--group=root'; + push @tarcmd, '--owner=0', '--group=0'; } } elsif (any { $_ eq $hook } ('essential', 'customize')) { if ($mode eq 'fakechroot') { @@ -2440,8 +2444,8 @@ sub hookhelper { # open a tar process that extracts the tarfile that we # supply it with on stdin to the output directory inside # the chroot - open $fh, '|-', @cmdprefix, @tarcmd, '--directory', - $directory, '--extract', '--file', + open $fh, '|-', @cmdprefix, @tarcmd, '--xattrs-include=*', + '--directory', $directory, '--extract', '--file', '-' // error "failed to fork(): $!"; } else { error "unknown command: $command"; @@ -3571,10 +3575,16 @@ sub main() { my $exitstatus = 0; my @taropts = ( - '--sort=name', "--mtime=\@$mtime", - '--clamp-mtime', '--numeric-owner', - '--one-file-system', '--xattrs', - '-c', '--exclude=./dev' + '--sort=name', + "--mtime=\@$mtime", + '--clamp-mtime', + '--numeric-owner', + '--one-file-system', + '--xattrs', + '--format=pax', + '--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime', + '-c', + '--exclude=./dev' ); # disable signals so that we can fork and change behaviour of the signal @@ -3925,7 +3935,11 @@ sub main() { # Open a tar process creating a tarfile of the instructed # path. To emulate the behaviour of cp, change to the # dirname of the requested path first. - open my $fh, '-|', 'tar', '--directory', + open my $fh, '-|', 'tar', '--numeric-owner', '--xattrs', + '--format=pax', + '--pax-option=exthdr.name=%d/PaxHeaders/%f,' + . 'delete=atime,delete=ctime', + '--directory', $msg eq 'mktar' ? dirname($indir) : $indir, '--create', '--file', '-', $msg eq 'mktar' ? basename($indir) : '.' @@ -3994,8 +4008,10 @@ sub main() { # now we expect one or more "write" messages containing the # tarball to unpack - open my $fh, '|-', 'tar', '--directory', $outdir, '--extract', - '--file', '-' // error "failed to fork(): $!"; + open my $fh, '|-', 'tar', '--numeric-owner', '--xattrs', + '--xattrs-include=*', '--directory', $outdir, + '--extract', '--file', + '-' // error "failed to fork(): $!"; # handle "write" messages from the child process and feed # their payload into the tar process until a "close" message