Blob Blame History Raw
From 80626ded3e849ba840ddd64c1713be5abb1c7449 Mon Sep 17 00:00:00 2001
From: Harald Hoyer <harald@redhat.com>
Date: Thu, 3 Jul 2014 12:52:58 +0200
Subject: [PATCH] Generate reproducible initramfs images

With the same source of files, it should be possible to generate the
same image file with every dracut run.

To accomplish this, we modify the timestamps of the files we generate at
runtime, call gzip with "-n" and cpio with "--reproducible".

The cpio --reproducible option is not yet upstream though, so if you
feel like it should be then please nag at the cpio mailing list.
http://lists.gnu.org/archive/html/bug-cpio/2014-08/msg00000.html
---
 dracut.8.asc      |  3 +++
 dracut.conf.5.asc |  3 +++
 dracut.sh         | 40 ++++++++++++++++++++++++++++++++++------
 3 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/dracut.8.asc b/dracut.8.asc
index 51a4e9f..44530bd 100644
--- a/dracut.8.asc
+++ b/dracut.8.asc
@@ -412,6 +412,9 @@ will not be able to boot.
     Do not compress the generated initramfs. This will override any other
     compression options.
 
+**--reproducible**::
+    Create reproducible images.
+
 **--list-modules**::
     List all available dracut modules.
 
diff --git a/dracut.conf.5.asc b/dracut.conf.5.asc
index 0b6be6a..9259951 100644
--- a/dracut.conf.5.asc
+++ b/dracut.conf.5.asc
@@ -179,6 +179,9 @@ provide a valid _/etc/fstab_.
 *i18n_install_all=*"__{yes|no}__"::
     Install everything regardless of generic or hostonly mode.
 
+*reproducible=*"__{yes|no}__"::
+    Create reproducible images.
+
 Files
 -----
 _/etc/dracut.conf_::
diff --git a/dracut.sh b/dracut.sh
index 1844336..2cce85b 100755
--- a/dracut.sh
+++ b/dracut.sh
@@ -191,6 +191,7 @@ Creates initial ramdisk images for preloading modules
   --printsize           Print out the module install size
   --sshkey [SSHKEY]     Add ssh key to initramfs (use with ssh-client module)
   --logfile [FILE]      Logfile to use (overrides configuration setting)
+  --reproducible        Create reproducible images
 
 If [LIST] has multiple arguments, then you have to put these in quotes.
 
@@ -372,6 +373,7 @@ rearrange_params()
         --long noimageifnotneeded \
         --long early-microcode \
         --long no-early-microcode \
+        --long reproducible \
         -- "$@")
 
     if (( $? != 0 )); then
@@ -557,7 +559,7 @@ while :; do
         --printsize)   printsize="yes";;
         --regenerate-all) regenerate_all="yes";;
         --noimageifnotneeded) noimageifnotneeded="yes";;
-
+        --reproducible) reproducible_l="yes";;
         --) shift; break;;
 
         *)  # should not even reach this point
@@ -801,6 +803,8 @@ stdloglvl=$((stdloglvl + verbosity_mod_l))
 [[ $early_microcode_l ]] && early_microcode=$early_microcode_l
 [[ $early_microcode ]] || early_microcode=no
 [[ $logfile_l ]] && logfile="$logfile_l"
+[[ $reproducible_l ]] && reproducible="$reproducible_l"
+
 # eliminate IFS hackery when messing with fw_dir
 fw_dir=${fw_dir//:/ }
 
@@ -810,7 +814,7 @@ case $compress in
     bzip2) compress="bzip2 -9";;
     lzma)  compress="lzma -9 -T0";;
     xz)    compress="xz --check=crc32 --lzma2=dict=1MiB -T0";;
-    gzip)  compress="gzip -9"; command -v pigz > /dev/null 2>&1 && compress="pigz -9";;
+    gzip)  compress="gzip -n -9 --rsyncable"; command -v pigz > /dev/null 2>&1 && compress="pigz -9 -n -T -R";;
     lzo)   compress="lzop -9";;
     lz4)   compress="lz4 -l -9";;
 esac
@@ -821,6 +825,8 @@ fi
 [[ $hostonly = yes ]] && hostonly="-h"
 [[ $hostonly != "-h" ]] && unset hostonly
 
+[[ $reproducible == yes ]] && DRACUT_REPRODUCIBLE=1
+
 readonly TMPDIR="$tmpdir"
 readonly initdir="$(mktemp --tmpdir="$TMPDIR/" -d -t initramfs.XXXXXX)"
 [ -d "$initdir" ] || {
@@ -1498,7 +1504,7 @@ if [[ $acpi_override = yes ]] && [[ -d $acpi_table_dir ]]; then
     mkdir -p $_dest_dir
     for table in $acpi_table_dir/*.aml; do
         dinfo "   Adding ACPI table: $table"
-        cp $table $_dest_dir
+        cp -a $table $_dest_dir
         create_early_cpio="yes"
     done
 fi
@@ -1512,15 +1518,37 @@ fi
 rm -f -- "$outfile"
 dinfo "*** Creating image file ***"
 
+if [[ $DRACUT_REPRODUCIBLE ]]; then
+    find "$initdir" -newer "$dracutbasedir/dracut-functions.sh" -print0 \
+        | xargs -r -0 touch -h -m -c -r "$dracutbasedir/dracut-functions.sh"
+
+    [[ "$(cpio --help)" == *--reproducible* ]] && CPIO_REPRODUCIBLE=1
+fi
+
 [[ "$UID" != 0 ]] && cpio_owner_root="-R 0:0"
 
 if [[ $create_early_cpio = yes ]]; then
     echo 1 > "$early_cpio_dir/d/early_cpio"
+
+    if [[ $DRACUT_REPRODUCIBLE ]]; then
+        find "$early_cpio_dir/d" -newer "$dracutbasedir/dracut-functions.sh" -print0 \
+            | xargs -r -0 touch -h -m -c -r "$dracutbasedir/dracut-functions.sh"
+    fi
+
     # The microcode blob is _before_ the initramfs blob, not after
-    (cd "$early_cpio_dir/d";     find . -print0 | cpio --null $cpio_owner_root -H newc -o --quiet > $outfile)
+    (
+        cd "$early_cpio_dir/d"
+        find . -print0 | sort -z \
+            | cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null $cpio_owner_root -H newc -o --quiet > $outfile
+    )
 fi
-if ! ( umask 077; cd "$initdir"; find . -print0 | cpio --null $cpio_owner_root -H newc -o --quiet | \
-    $compress >> "$outfile"; ); then
+
+if ! (
+        umask 077; cd "$initdir"
+        find . -print0 | sort -z \
+            | cpio ${CPIO_REPRODUCIBLE:+--reproducible} --null $cpio_owner_root -H newc -o --quiet \
+            | $compress >> "$outfile"
+    ); then
     dfatal "dracut: creation of $outfile failed"
     exit 1
 fi