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
This commit is contained in:
Johannes 'josch' Schauer 2020-01-21 13:24:49 +01:00
parent a1df1a9730
commit 64fedc530e
Signed by untrusted user: josch
GPG key ID: F2CBA5C78FBD83E1
2 changed files with 30 additions and 14 deletions

View file

@ -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

View file

@ -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