From a599f50e480e8755d61f515c4351ee2dd33d89a3 Mon Sep 17 00:00:00 2001 From: Roland Clobus Date: Wed, 12 Jan 2022 16:21:36 +0100 Subject: [PATCH] Add hooks for building reproducible images --- ...-function-uuid_generate_random.hook.chroot | 63 +++++++++++++++++++ .../1001-reproducible-fontconfig.hook.chroot | 25 ++++++++ .../1002-reproducible-mdadm.hook.chroot | 21 +++++++ .../1003-reproducible-plymouth.hook.chroot | 27 ++++++++ ...4-reproducible-libxml-sax-perl.hook.chroot | 28 +++++++++ .../9000-cleanup-ucf-backup-files.hook.chroot | 7 +++ ...e-cleanup-uuid_generate_random.hook.chroot | 6 ++ examples/hooks/reproducible/README | 11 ++++ 8 files changed, 188 insertions(+) create mode 100755 examples/hooks/reproducible/1000-reproducible-function-uuid_generate_random.hook.chroot create mode 100755 examples/hooks/reproducible/1001-reproducible-fontconfig.hook.chroot create mode 100755 examples/hooks/reproducible/1002-reproducible-mdadm.hook.chroot create mode 100755 examples/hooks/reproducible/1003-reproducible-plymouth.hook.chroot create mode 100755 examples/hooks/reproducible/1004-reproducible-libxml-sax-perl.hook.chroot create mode 100755 examples/hooks/reproducible/9000-cleanup-ucf-backup-files.hook.chroot create mode 100755 examples/hooks/reproducible/9900-reproducible-cleanup-uuid_generate_random.hook.chroot create mode 100644 examples/hooks/reproducible/README diff --git a/examples/hooks/reproducible/1000-reproducible-function-uuid_generate_random.hook.chroot b/examples/hooks/reproducible/1000-reproducible-function-uuid_generate_random.hook.chroot new file mode 100755 index 000000000..afdef6c3e --- /dev/null +++ b/examples/hooks/reproducible/1000-reproducible-function-uuid_generate_random.hook.chroot @@ -0,0 +1,63 @@ +#!/bin/sh +set -e + +# util-linux creates random UUIDs when uuid_generate_random is called +# Use LD_PRELOAD to replace uuid_generate_random with a less random version + +# Don't run if gcc is not installed +if [ ! -e /usr/bin/cc ]; +then + exit 0 +fi + +cat > unrandomize_uuid_generate_random.c << END_OF_SOURCE +#include +#include + +#define SEQUENCE_FILENAME "/var/cache/unrandomize_uuid_generate_random.sequence_number" + +/* https://tools.ietf.org/html/rfc4122 */ +typedef unsigned char uuid_t[16]; + +/* Our pseudo-random version */ +void uuid_generate_random(uuid_t out) +{ + /* Nil UUID */ + for (int i=0;i<16;i++) { + out[i] = 0x00; + } + out[6]=0x40; /* UUID version 4 means randomly generated */ + out[8]=0x80; /* bit7=1,bit6=0 */ + + /* The file doesn't need to exist yet */ + FILE *f = fopen(SEQUENCE_FILENAME, "rb"); + if (f) { + fread(out+12, 4, 1, f); + fclose(f); + } + /* Use the next number. Endianness is not important */ + (*(unsigned long*)(out+12))++; + + unsigned long long epoch; + /* Use SOURCE_DATE_EPOCH when provided */ + char *date = getenv("SOURCE_DATE_EPOCH"); + if (date) { + epoch = strtoll(date, NULL, 10); + } else { + epoch = 0ll; + } + out[0] = (epoch & 0xFF000000) >> 24; + out[1] = (epoch & 0x00FF0000) >> 16; + out[2] = (epoch & 0x0000FF00) >> 8; + out[3] = (epoch & 0x000000FF); + + /* Write the sequence number */ + f = fopen(SEQUENCE_FILENAME, "wb"); + if (f) { + fwrite(out+12, 4, 1, f); + fclose(f); + } +} +END_OF_SOURCE +/usr/bin/cc -shared -fPIC unrandomize_uuid_generate_random.c -Wall --pedantic -o /usr/lib/unrandomize_uuid_generate_random.so +rm -f unrandomize_uuid_generate_random.c diff --git a/examples/hooks/reproducible/1001-reproducible-fontconfig.hook.chroot b/examples/hooks/reproducible/1001-reproducible-fontconfig.hook.chroot new file mode 100755 index 000000000..978ba0c49 --- /dev/null +++ b/examples/hooks/reproducible/1001-reproducible-fontconfig.hook.chroot @@ -0,0 +1,25 @@ +#!/bin/sh +set -e + +# fontconfig creates non-reproducible files with UUIDs +# See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864082 +# +# Because the UUIDs should not be deleted, the proposed work-around is: +# * Use LD_PRELOAD to replace uuid_generate_random with a less random version + +# Don't run if fontconfig is not installed +if [ ! -e /usr/bin/fc-cache ]; +then + exit 0 +fi + +# Don't run if the LD_PRELOAD module is not compiled +if [ ! -e /usr/lib/unrandomize_uuid_generate_random.so ]; +then + echo "P: $(basename $0) Reproducible hook inactive: The UUID module was not found" + exit 0 +fi + +LD_PRELOAD=/usr/lib/unrandomize_uuid_generate_random.so /usr/bin/fc-cache --force --really-force --system-only --verbose + +echo "P: $(basename $0) Reproducible hook has been applied" diff --git a/examples/hooks/reproducible/1002-reproducible-mdadm.hook.chroot b/examples/hooks/reproducible/1002-reproducible-mdadm.hook.chroot new file mode 100755 index 000000000..90569b3ae --- /dev/null +++ b/examples/hooks/reproducible/1002-reproducible-mdadm.hook.chroot @@ -0,0 +1,21 @@ +#!/bin/sh +set -e + +# mkconf of mdadm creates a file with a timestamp +# A bug report with patch is available at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=982607 +# This script duplicates that patch + +# Don't run if mdadm is not installed +if [ ! -e /usr/share/mdadm/mkconf ]; +then + exit 0 +fi + +# If mkconf already contains references to SOURCE_DATE_EPOCH, there is no need to patch the file +if grep -q SOURCE_DATE_EPOCH /usr/share/mdadm/mkconf; +then + exit 0 +fi +sed -i -e '/# This configuration was auto-generated on/cif [ -z $SOURCE_DATE_EPOCH ]; then\n echo "# This configuration was auto-generated on $(date -R) by mkconf"\nelse\n echo "# This configuration was auto-generated on $(date -R --utc -d@$SOURCE_DATE_EPOCH) by mkconf"\nfi' /usr/share/mdadm/mkconf + +echo "P: $(basename $0) Reproducible hook has been applied" diff --git a/examples/hooks/reproducible/1003-reproducible-plymouth.hook.chroot b/examples/hooks/reproducible/1003-reproducible-plymouth.hook.chroot new file mode 100755 index 000000000..da1bd423e --- /dev/null +++ b/examples/hooks/reproducible/1003-reproducible-plymouth.hook.chroot @@ -0,0 +1,27 @@ +#!/bin/sh +set -e + +# The hook of plymouth in update-initramfs calls fc-cache + +# Don't run if plymouth is not installed +if [ ! -e /usr/share/initramfs-tools/hooks/plymouth ]; +then + exit 0 +fi + +# If the hook already contains references to LD_PRELOAD, there is no need to patch the file +if grep -q LD_PRELOAD /usr/share/initramfs-tools/hooks/plymouth; +then + exit 0 +fi + +# Don't patch if the LD_PRELOAD module is not compiled +if [ ! -e /usr/lib/unrandomize_uuid_generate_random.so ]; +then + echo "P: $(basename $0) Reproducible hook inactive: The UUID module was not found" + exit 0 +fi + +sed -i -e 's|fc-cache -s|LD_PRELOAD=/usr/lib/unrandomize_uuid_generate_random.so fc-cache|' /usr/share/initramfs-tools/hooks/plymouth + +echo "P: $(basename $0) Reproducible hook has been applied" diff --git a/examples/hooks/reproducible/1004-reproducible-libxml-sax-perl.hook.chroot b/examples/hooks/reproducible/1004-reproducible-libxml-sax-perl.hook.chroot new file mode 100755 index 000000000..f28c55df3 --- /dev/null +++ b/examples/hooks/reproducible/1004-reproducible-libxml-sax-perl.hook.chroot @@ -0,0 +1,28 @@ +#!/bin/sh +set -e + +# update-perl-sax-parsers of libxml-sax-perl creates a file with a random order of its lines +# A bug report with patch is available at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993444 +# This script duplicates that patch + +# Don't run if libxml-sax-perl is not installed +if [ ! -e /usr/bin/update-perl-sax-parsers ]; +then + exit 0 +fi + +# If Debian.pm already contains a sort line, there is no need to patch the file +if grep -q sort /usr/share/perl5/XML/SAX/Debian.pm; +then + exit 0 +fi + +# Patch the Perl script +sed -i -e '/foreach my $key/s/keys/sort keys/' /usr/share/perl5/XML/SAX/Debian.pm + +# Regenerate the file that has more than one key-value pair +update-perl-sax-parsers --remove XML::SAX::Expat +update-perl-sax-parsers --add XML::SAX::Expat --priority 50 +update-perl-sax-parsers --update + +echo "P: $(basename $0) Reproducible hook has been applied" diff --git a/examples/hooks/reproducible/9000-cleanup-ucf-backup-files.hook.chroot b/examples/hooks/reproducible/9000-cleanup-ucf-backup-files.hook.chroot new file mode 100755 index 000000000..902707f5a --- /dev/null +++ b/examples/hooks/reproducible/9000-cleanup-ucf-backup-files.hook.chroot @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +# Delete all older backups of ucf files +# The current files are /var/lib/ucf/hashfile and /var/lib/ucf/registry +rm -f /var/lib/ucf/hashfile.* +rm -f /var/lib/ucf/registry.* diff --git a/examples/hooks/reproducible/9900-reproducible-cleanup-uuid_generate_random.hook.chroot b/examples/hooks/reproducible/9900-reproducible-cleanup-uuid_generate_random.hook.chroot new file mode 100755 index 000000000..250e253ef --- /dev/null +++ b/examples/hooks/reproducible/9900-reproducible-cleanup-uuid_generate_random.hook.chroot @@ -0,0 +1,6 @@ +#!/bin/sh +set -e + +# Remove the module and its data file +rm -f /usr/lib/unrandomize_uuid_generate_random.so +rm -f /var/cache/unrandomize_uuid_generate_random.sequence_number diff --git a/examples/hooks/reproducible/README b/examples/hooks/reproducible/README new file mode 100644 index 000000000..9324fd2e3 --- /dev/null +++ b/examples/hooks/reproducible/README @@ -0,0 +1,11 @@ +Use these scripts to generate reproducible images. + +See the generic Wiki page: https://wiki.debian.org/ReproducibleInstalls/LiveImages + +After 'lb config' and before 'lb build' you should copy these hooks: + +cp /usr/share/doc/live-build/examples/hooks/reproducible/* config/hooks/normal + +or (when using the latest git version): + +cp $LIVE_BUILD/examples/hooks/reproducible/* config/hooks/normal