#991928 grub2: reproducible builds: embeds different strings depending on (obscure) locales

Package:
src:grub2
Source:
grub2
Submitter:
Vagrant Cascadian
Date:
2026-07-16 19:41:03 UTC
Severity:
minor
Tags:
#991928#5
Date:
2021-08-05 22:11:02 UTC
From:
To:
Some locales (e.g. potentially obscure locales used by reprotest) may
cause sort order issues in embedded strings in some of the grub-*.bin
binaries.


The attached patch fixes this by exporting LC_ALL=C.UTF-8 from
debian/rules.


There are still several other outstanding issues affecting the
reproducibility of grub2, but this should help reduce the differences to
troubleshoot the remaining issues.


Thanks for maintaining grub2!


live well,
  vagrant

#991928#10
Date:
2024-10-19 14:18:56 UTC
From:
To:
Dear Maintainer, Vagrant,

I'm not 100% confident, but I believe that this bug may have been fixed upstream
as part of a subsequent release.  I don't find any clearly locale-related
differences when comparing the current output of the comparative builds[1] of
grub2 in the Reproducible Builds test infrastructure for Debian.

The upstream commit that I think is the most likely candidate to have fixed
the problem is this one:

http://git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=f42266a8a2a4215e4ffe419b8092bdf9ced33e8e

...but I haven't tested / confirmed that.

Regards,
James

[1] - https://tests.reproducible-builds.org/debian/rb-pkg/unstable/amd64/diffoscope-results/grub2.html

#991928#15
Date:
2024-10-20 02:40:27 UTC
From:
To:
I would be very pleasantly surprised...

The locales tested in the test infrastructure do not trigger the issue.

Current versions of reprotest no longer randomizes locales and defaults
to testing using the et_EE.UTF-8 locale (which also does not trigger the
issue), but I seem to recall one of these *not* UTF-8 locales that was
the trigger:

  ru_RU.CP1251 kk_KZ.RK1048

Current reprotest allows specifying the locale to test:

  reprotest --vary=+locales,locales.locale=kk_KZ.RK1048


With all those caveats, this is definitely a very minor issue (even
moreso than when originally filed due to changes in reprotest), although
easily worked around by always specifying the C.UTF-8 locale from
debian/rules.

That seems only related to the C or C.UTF-8 locales, so seems unlikely
to fix the issue...


live well,
  vagrant

#991928#20
Date:
2024-10-22 10:06:44 UTC
From:
To:
On Sun, Oct 20, 2024, 03:40 Vagrant Cascadian < vagrant@reproducible-builds.org> wrote:

Ok, that likely explains it.  I'll run the reprotest variations you
suggested (ideally both without, and then with, the patch applied) soon to
confirm that.

Thanks!
James

#991928#25
Date:
2024-11-10 21:02:13 UTC
From:
To:
Hi Vagrant,

I've spent some time attempting rebuilds, but am having difficulty
replicating this bug.  I do find some nondeterministic results, but
they don't appear to be related to locales (one is a chmod/file
permission error -- one is a timestamp, and there may be another in
there that I'm yet to determine).

I have been using "--vary=-all,+locales,locales.locale=..." with the
suggested locale codes, and I've installed the Debian "locales" and
"locales-all" packages in addition to the base build-deps for grub2
itself.

Are there any additional steps required for the build nondeterminism
to appear?  As a follow-up task I may attempt rebuilds from older
snapshots around the time of the bugreport -- but perhaps there's
something I'm missing.

Thanks again,
James

#991928#30
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