#787795 grub2: please build rescue ISO and floppy reproducibly

Package:
grub2
Source:
grub2
Description:
GRand Unified Bootloader, version 2 (dummy package)
Submitter:
Daniel Kahn Gillmor
Date:
2026-07-16 19:41:02 UTC
Severity:
wishlist
Tags:
#787795#5
Date:
2015-06-05 06:37:38 UTC
From:
To:
The ISOs (/usr/lib/grub-rescue/grub-rescue-cdrom.iso and
/usr/lib/grub-rescue/grub-rescue-floppy.iso) that are created by the
grub build process embed subtle variations in the timestamps and the
extents of each file.

This is one of the things that keeps the package from producing
byte-for-byte identical binary builds.

(see https://reproducible.debian.net/rb-pkg/unstable/amd64/grub2.html)

I think this can be fixed with a couple steps in debian/rules: sort
the files by extent, and fix the timestamps.  See some of the scripts
sketched here for example:

https://lists.gnu.org/archive/html/bug-xorriso/2015-06/msg00013.html

However, it won't be completely reproducible until we get a newer
version of xorriso in debian so that we can "-alter_date_r c" (see
#787793, which blocks this bug).

Note that there are other parts of the package which are also
unreproducible (/usr/share/qemu/grub.bin and
usr/lib/grub-xen/grub-i386-xen.bin binaries differ in ways i have not
examined, and there are timestamps in
usr/share/info/grub-dev.info.gz).  These probably will be covered with
separate bug reports.

Regards,

#787795#20
Date:
2015-12-04 17:57:29 UTC
From:
To:
I've send a patches regarding reproducible builds.

debian/rules uses mkrescue and it's uuid comes from a timestamp.

https://lists.gnu.org/archive/html/grub-devel/2015-12/msg00015.html

#787795#25
Date:
2021-07-25 23:19:46 UTC
From:
To:
Looking at recent diffoscope output:

https://tests.reproducible-builds.org/debian/rb-pkg/bullseye/amd64/diffoscope-results/grub2.html

It appears for the .iso files only the timestamp issue remains.

Since newer versions of xorriso are now in Debian, I tried adding
"-alter_date_r c" to xorriso calls, but it would seem xorriso doesn't
support "-alter_date_r c" when used with "-as mkisofs". I'm not sure how
difficult it would be to convert away from using "-as mkisofs" so that
"-alter_date_r c" would be supportable...


live well,
  vagrant

#787795#30
Date:
2024-10-02 11:05:20 UTC
From:
To:
Hi,
and xorrisofs (aka "xorriso -as mkisofs").. although it may in theory be
possible to convert to 'native' xorriso by migrating a lot of the command-line
construction, I think that it might be fragile and unnecessary work, because:

...there is a '--set_all_file_dates' command-line option[1] in xorrisofs that
seems to do what we want here.

There's one other change required in grub-mkrescue alongside this in order to
achieve reproducible builds: we need it to read from the SOURCE_DATE_EPOCH env
var when set (currently grub-mkrescue always uses system clock time).

Please find attached a patch that allows me to rebuild grub-rescue-cdrom.iso
deterministically on my local machine when SOURCE_DATE_EPOCH is set.  I'll also
offer this as a merge request on the Salsa repository[2].

Note: the current patch _always_ adds the set_all_file_dates option when
invoking xorriso, regardless of whether the image creation time is read from
the SOURCE_DATE_EPOCH variable or the system clock.

Regards,
James

[1] - https://manpages.debian.org/bookworm/xorriso/xorrisofs.1.en.html#set_all_file_dates

[2] - https://salsa.debian.org/grub-team/grub/

#787795#37
Date:
2024-10-02 11:30:08 UTC
From:
To:

#787795#44
Date:
2026-06-01 20:34:04 UTC
From:
To:
I can confirm that this still applies for grub2 2.14-2, still is needed,
and fixes the issue. Thanks!

So that is one more known fix for grub2 reproducibility...

live well,
  vagrant

#787795#49
Date:
2026-07-16 19:39:29 UTC
From:
To:
I have uploaded an NMU to DELAYED/10 with the following changes:

diff -Nru grub2-2.14/debian/changelog grub2-2.14/debian/changelog
--- grub2-2.14/debian/changelog	2026-06-23 08:04:12.000000000 -0700
+++ grub2-2.14/debian/changelog	2026-07-16 11:45:44.000000000 -0700
@@ -1,3 +1,24 @@
+grub2 (2.14-3.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+
+  [ Vagrant Cascadian ]
+  * Remove updated timestamps from grub.texi and grub-dev.texi.
+    (Closes: #991926)
+  * debian/rules: Sort calls to find when generating lintian overrides.
+    (Closes: #1138608)
+  * debian/rules: pass SHELL=/bin/bash to configure. (Closes: #991927)
+  * debian/rules: export LC_ALL=C.UTF-8 to ensure consistent sort order.
+    (Closes: #991928)
+  * debian/platform-subst: Use sorted list of cpu_platforms.
+    (Closes: #1138611)
+
+  [ James Addison ]
+  * grub2: please build rescue ISO and floppy reproducibly.
+    (Closes: #787795)
+
+ -- Vagrant Cascadian <vagrant@reproducible-builds.org>  Thu, 16 Jul 2026 11:45:44 -0700
+
 grub2 (2.14-3) unstable; urgency=medium

   * Really do not append file/line prefixes to error message
diff -Nru grub2-2.14/debian/patches/bug787795-grub2-please-build-rescue-iso-.patch grub2-2.14/debian/patches/bug787795-grub2-please-build-rescue-iso-.patch
--- grub2-2.14/debian/patches/bug787795-grub2-please-build-rescue-iso-.patch	1969-12-31 16:00:00.000000000 -0800
+++ grub2-2.14/debian/patches/bug787795-grub2-please-build-rescue-iso-.patch	2026-07-16 11:45:44.000000000 -0700
@@ -0,0 +1,104 @@
+From: James Addison <jay@jp-hosting.net>
+Date: Wed, 2 Oct 2024 12:05:20 +0100
+X-Dgit-Generated: 2.14-3.1 db24136aef7571551a9cbad0b6e743297d759f30
+Subject: Bug#787795: grub2: please build rescue ISO and floppy reproducibly
+
+Package: grub2
+Followup-For: Bug #787795
+X-Debbugs-Cc: dkg@fifthhorseman.net, vagrant@reproducible-builds.org
+Control: tags -1 patch
+
+Hi,
+
+On Fri, 05 Jun 2015 02:37:38 -0400, Daniel wrote:
+> > However, it won't be completely reproducible until we get a newer
+> > version of xorriso in debian so that we can "-alter_date_r c" (see
+> > #787793, which blocks this bug).
+
+On Sun, 25 Jul 2021 16:19:46 -0700, Vagrant wrote:
+> Since newer versions of xorriso are now in Debian, I tried adding
+> "-alter_date_r c" to xorriso calls, but it would seem xorriso doesn't
+> support "-alter_date_r c" when used with "-as mkisofs". I'm not sure how
+> difficult it would be to convert away from using "-as mkisofs" so that
+> "-alter_date_r c" would be supportable...
+
+>From inspecting the grub codebase and the commandline options to both xorriso
+and xorrisofs (aka "xorriso -as mkisofs").. although it may in theory be
+possible to convert to 'native' xorriso by migrating a lot of the command-line
+construction, I think that it might be fragile and unnecessary work, because:
+
+...there is a '--set_all_file_dates' command-line option[1] in xorrisofs that
+seems to do what we want here.
+
+There's one other change required in grub-mkrescue alongside this in order to
+achieve reproducible builds: we need it to read from the SOURCE_DATE_EPOCH env
+var when set (currently grub-mkrescue always uses system clock time).
+
+Please find attached a patch that allows me to rebuild grub-rescue-cdrom.iso
+deterministically on my local machine when SOURCE_DATE_EPOCH is set.  I'll also
+offer this as a merge request on the Salsa repository[2].
+
+Note: the current patch _always_ adds the set_all_file_dates option when
+invoking xorriso, regardless of whether the image creation time is read from
+the SOURCE_DATE_EPOCH variable or the system clock.
+
+Regards,
+James
+
+[1] - https://manpages.debian.org/bookworm/xorriso/xorrisofs.1.en.html#set_all_file_dates
+
+[2] - https://salsa.debian.org/grub-team/grub/
+
+From: James Addison <jay@jp-hosting.net>
+Date: Tue, 01 Oct 2024 22:36:39 +0100
+Subject: grub2: build rescue ISO reproducibly
+
+Extend the xorriso command-line invocation to configure a specific
+timestamp for all files during creation of Grub rescue ISO images.
+
+The timestamp to use is read from the SOURCE_DATE_EPOCH environment
+variable when it is set.
+
+Bug-Debian: https://bugs.debian.org/787795
+
+---
+
+diff --git a/util/grub-mkrescue.c b/util/grub-mkrescue.c
+index e7b9078ab..d003f78d9 100644
+--- a/util/grub-mkrescue.c
++++ b/util/grub-mkrescue.c
+@@ -580,7 +580,13 @@ main (int argc, char *argv[])
+   {
+     time_t tim;
+     struct tm *tmm;
+-    tim = time (NULL);
++    /* https://reproducible-builds.org/docs/source-date-epoch/ */
++    char *source_date_epoch;
++    /* This assumes that the SOURCE_DATE_EPOCH environment variable will contain
++       a correct, positive integer in the time_t range */
++    if ((source_date_epoch = getenv("SOURCE_DATE_EPOCH")) == NULL ||
++        (tim = (time_t)strtoll(source_date_epoch, NULL, 10)) <= 0)
++            time(&tim);
+     tmm = gmtime (&tim);
+     iso_uuid = xmalloc (55);
+     grub_snprintf (iso_uuid, 50,
+@@ -604,6 +610,19 @@ main (int argc, char *argv[])
+     xorriso_push (uuid_out);
+     free (uuid_out);
+   }
++  {
++    char *uuid_out = xmalloc (strlen (iso_uuid) + 1);
++    char *optr;
++    const char *iptr;
++    optr = grub_stpcpy (uuid_out, "");
++    for (iptr = iso_uuid; *iptr; iptr++)
++      if (*iptr != '-')
++	*optr++ = *iptr;
++    *optr = '\0';
++    xorriso_push ("--set_all_file_dates");
++    xorriso_push (uuid_out);
++    free (uuid_out);
++  }
+
+   /* build BIOS core.img.  */
+   if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC])
diff -Nru grub2-2.14/debian/patches/remove-updated-timestamps-from-grub.texi.patch grub2-2.14/debian/patches/remove-updated-timestamps-from-grub.texi.patch
--- grub2-2.14/debian/patches/remove-updated-timestamps-from-grub.texi.patch	1969-12-31 16:00:00.000000000 -0800
+++ grub2-2.14/debian/patches/remove-updated-timestamps-from-grub.texi.patch	2026-07-16 11:45:44.000000000 -0700
@@ -0,0 +1,60 @@
+From: Vagrant Cascadian <vagrant@reproducible-builds.org>
+Date: Mon, 26 Jul 2021 00:05:21 +0000
+X-Dgit-Generated: 2.14-3.1 d03314ddf945eda65d2cc27e1518dcb4786faeca
+Subject: Remove updated timestamps from grub.texi and grub-dev.texi
+
+The timestamps are embedded in the documentation at build time, which
+does not accurately reflect when the documentation was last updated,
+and obviously causes issues for reproducible builds to embed the build
+time.
+
+https://reproducible-builds.org/docs/timestamps/
+
+---
+
+diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
+index 51a0923ec..bbd54b7d6 100644
+--- a/docs/grub-dev.texi
++++ b/docs/grub-dev.texi
+@@ -17,8 +17,7 @@
+ @finalout
+
+ @copying
+-This developer manual is for GNU GRUB (version @value{VERSION},
+-@value{UPDATED}).
++This developer manual is for GNU GRUB (version @value{VERSION}).
+
+ Copyright @copyright{} 1999,2000,2001,2002,2004,2005,2006,2008,2009,2010,2011 Free Software Foundation, Inc.
+
+@@ -40,7 +39,7 @@ Invariant Sections.
+ @titlepage
+ @sp 10
+ @title the GNU GRUB developer manual
+-@subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}.
++@subtitle The GRand Unified Bootloader, version @value{VERSION}.
+ @author Yoshinori K. Okuji
+ @author Colin D Bennett
+ @author Vesa Jääskeläinen
+diff --git a/docs/grub.texi b/docs/grub.texi
+index 78b530833..79f200e75 100644
+--- a/docs/grub.texi
++++ b/docs/grub.texi
+@@ -17,8 +17,7 @@
+ @finalout
+
+ @copying
+-This manual is for GNU GRUB (version @value{VERSION},
+-@value{UPDATED}).
++This manual is for GNU GRUB (version @value{VERSION}).
+
+ Copyright @copyright{} 1999,2000,2001,2002,2004,2006,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+
+@@ -48,7 +47,7 @@ Invariant Sections.
+ @titlepage
+ @sp 10
+ @title the GNU GRUB manual
+-@subtitle The GRand Unified Bootloader, version @value{VERSION}, @value{UPDATED}.
++@subtitle The GRand Unified Bootloader, version @value{VERSION}.
+ @author Gordon Matzigkeit
+ @author Yoshinori K. Okuji
+ @author Colin Watson
diff -Nru grub2-2.14/debian/patches/series grub2-2.14/debian/patches/series
--- grub2-2.14/debian/patches/series	2026-06-23 07:54:03.000000000 -0700
+++ grub2-2.14/debian/patches/series	2026-07-16 11:45:44.000000000 -0700
@@ -69,3 +69,5 @@
 grub-install-removable-shim.patch
 upstream/efi-chainloader-set-loaded-image-device-path.patch
 upstream/efi-linux-set-loaded-image-device-path.patch
+remove-updated-timestamps-from-grub.texi.patch
+bug787795-grub2-please-build-rescue-iso-.patch
diff -Nru grub2-2.14/debian/platform-subst grub2-2.14/debian/platform-subst
--- grub2-2.14/debian/platform-subst	2026-06-19 07:19:05.000000000 -0700
+++ grub2-2.14/debian/platform-subst	2026-07-16 11:45:44.000000000 -0700
@@ -14,9 +14,10 @@
 my $grub_dir_path = "debian/tmp-$package/usr/lib/grub";
 opendir my $grub_dir, $grub_dir_path or die "can't opendir $grub_dir_path: $!";
 my @cpu_platforms = grep { !/^\./ } readdir $grub_dir;
+my @cpu_platforms_sorted = sort @cpu_platforms;
 closedir $grub_dir;

-$subst{FIRST_CPU_PLATFORM} = $cpu_platforms[0];
+$subst{FIRST_CPU_PLATFORM} = $cpu_platforms_sorted[0];

 sub emit ($) {
 	my $line = shift;
diff -Nru grub2-2.14/debian/rules grub2-2.14/debian/rules
--- grub2-2.14/debian/rules	2026-06-19 07:19:05.000000000 -0700
+++ grub2-2.14/debian/rules	2026-07-16 11:45:44.000000000 -0700
@@ -29,6 +29,7 @@
 export HOST_LDFLAGS
 export TARGET_CPPFLAGS := -Wno-unused-but-set-variable
 export TARGET_LDFLAGS := -no-pie
+export LC_ALL=C.UTF-8

 # upstream changed the tests to hard errors instead of skips when not running as root, so mark them
 # as expected failure.
@@ -52,6 +53,7 @@
 confflags = \
 	PACKAGE_VERSION="$(deb_version)" PACKAGE_STRING="GRUB $(deb_version)" \
 	CC=$(CC) TARGET_CC=$(CC) \
+	SHELL=/bin/bash \
 	--libdir=\$${prefix}/lib --libexecdir=\$${prefix}/lib \
 	--enable-grub-mkfont \
 	--disable-grub-emu-usb \
@@ -439,10 +441,10 @@
 	mkdir -p debian/$(package_bin)/usr/share/lintian/overrides
 	echo "$(package_bin): unstripped-binary-or-object [*.mod]" \
 		>> debian/$(package_bin)/usr/share/lintian/overrides/$(package_bin)
-	cd debian/tmp-$(package) && find usr/lib/grub -name kernel.img \
+	cd debian/tmp-$(package) && find usr/lib/grub -name kernel.img | sort \
 		| sed -e "s%.*%$(package_bin): statically-linked-binary [&]%g" \
 	>> $(CURDIR)/debian/$(package_bin)/usr/share/lintian/overrides/$(package_bin)
-	cd debian/tmp-$(package) && find usr/lib/grub -name kernel.img \
+	cd debian/tmp-$(package) && find usr/lib/grub -name kernel.img | sort \
 		| sed -e "s%.*%$(package_bin): unstripped-binary-or-object [&]%g" \
 	>> $(CURDIR)/debian/$(package_bin)/usr/share/lintian/overrides/$(package_bin)
 	if ([ "$@" = "install/grub-efi-amd64" ] && [ "$(DEB_HOST_ARCH_CPU)" = "i386" ]) || \
@@ -450,7 +452,7 @@
 	   [ "$@" = "install/grub-xen" ]; then \
 		echo "$(package_bin): binary-from-other-architecture [*.mod]" \
 			>> debian/$(package_bin)/usr/share/lintian/overrides/$(package_bin) ; \
-		cd debian/tmp-$(package) && find usr/lib/grub -name kernel.img \
+		cd debian/tmp-$(package) && find usr/lib/grub -name kernel.img | sort \
 			| sed -e "s%.*%$(package_bin): binary-from-other-architecture [&]%g" \
 		>> $(CURDIR)/debian/$(package_bin)/usr/share/lintian/overrides/$(package_bin) ; \
 	fi
@@ -482,7 +484,7 @@
 		>> debian/$(package_dbg)/usr/share/lintian/overrides/$(package_dbg)
 	echo "$(package_dbg): statically-linked-binary [*.image]" \
 		>> debian/$(package_dbg)/usr/share/lintian/overrides/$(package_dbg)
-	cd debian/tmp-$(package) && find usr/lib/grub -name kernel.exec \
+	cd debian/tmp-$(package) && find usr/lib/grub -name kernel.exec | sort \
 		| sed -e "s%.*%$(package_dbg): statically-linked-binary [&]%g" \
 	>> $(CURDIR)/debian/$(package_dbg)/usr/share/lintian/overrides/$(package_dbg)
 	if ([ "$@" = "install/grub-efi-amd64" ] && [ "$(DEB_HOST_ARCH_CPU)" = "i386" ]) || \
@@ -490,7 +492,7 @@
 	   [ "$@" = "install/grub-xen" ] ; then \
 		echo "$(package_dbg): binary-from-other-architecture [*.module]" \
 			>> debian/$(package_dbg)/usr/share/lintian/overrides/$(package_dbg) ; \
-		cd debian/tmp-$(package) && find usr/lib/grub -name kernel.exec \
+		cd debian/tmp-$(package) && find usr/lib/grub -name kernel.exec | sort \
 			| sed -e "s%.*%$(package_dbg): binary-from-other-architecture [&]%g" \
 		>> $(CURDIR)/debian/$(package_dbg)/usr/share/lintian/overrides/$(package_dbg) ; \
 	fi


live well,
  vagrant