LLM (Claude) consulted context:

Summary:
available_ids() in /usr/lib/grub/grub-multi-install deduplicates multiple 
/dev/disk/by-id/* aliases for the same physical device via sort -k2 -s -u, 
keyed on the resolved realpath. Because the key is identical for all aliases of 
one device, the stable sort's tie-break falls through to the original iteration 
order of the /dev/disk/by-id/* glob — and glob expansion order is 
locale-collation-dependent (LC_COLLATE). No locale is pinned anywhere in the 
script, so which by-id alias is selected as "canonical" for a given device 
depends on the invoking shell's ambient locale.

Impact:
grub-efi/install_devices is user/administrator-facing persistent debconf state, 
consulted and rewritten on every grub-efi-* postinst run (fresh install, 
upgrade, dpkg-reconfigure). On systems with multiple ESPs where by-id aliasing 
is ambiguous (e.g. NVMe devices exposing both nvme-eui.* and 
nvme-<model>_<serial>-part* names for the same namespace), the set of physical 
devices targeted for GRUB installation doesn't change across runs, but the 
specific alias string stored for each device can — purely as a function of 
which locale happened to be active during that particular postinst/reconfigure 
invocation. This:

* produces spurious/inconsistent install_devices values across 
otherwise-identical maintenance operations,
* makes the stored debconf value unsuitable as a stable identifier for any 
tooling (fleet management, OTA scripts, config auditing) that compares it 
across runs rather than resolving each entry to a realpath before comparing,
* is silent — nothing surfaces to the administrator indicating the alias 
changed underneath them.

Steps to reproduce:

* On a system with ≥2 ESP-typed partitions where at least one backing device 
exposes multiple /dev/disk/by-id/* aliases for the same partition (e.g. NVMe 
with both EUI and model/serial naming schemes),
* sudo LC_ALL=C dpkg-reconfigure grub-efi-arm64, note the resulting 
debconf-show grub-efi-arm64 | grep install_devices output,
* sudo LC_ALL=en_US.UTF-8 dpkg-reconfigure grub-efi-arm64 (with en_US.UTF-8 
generated/available), note the output again,
* Compare.

Actual result:

LC_ALL=C:
  grub-efi/install_devices: 
/dev/disk/by-id/nvme-Micron_7450_MTFDKBA480TFR_254954CD71E8-part1, 
/dev/disk/by-id/nvme-Micron_7450_MTFDKBA480TFR_254954CD7CF6-part1

LC_ALL=en_US.UTF-8:
  grub-efi/install_devices: 
/dev/disk/by-id/nvme-eui.000000000000000100a0752554cd71e8-part1, 
/dev/disk/by-id/nvme-eui.000000000000000100a0752554cd7cf6-part1

Expected result:
The stored value for a given set of physical devices should be identical 
regardless of the invoking locale.

Root cause:
In available_ids() (/usr/lib/grub/grub-multi-install):

sh
cached_available_ids="$(
    for path in /dev/disk/by-id/*; do
      [ -e "$path" ] || continue
      printf '%s %s\n' "$path" "$(readlink -f "$path")"
    done | sort -k2 -s -u | cut -d' ' -f1
  )"

No LC_COLLATE/LC_ALL is pinned before the glob or the sort. sort -s -u
on a tied key (field 2, the realpath) preserves first-seen input order —
so the result depends entirely on the shell's glob expansion order for
/dev/disk/by-id/*, which is strcoll()-based and locale-sensitive.

Suggested fix:
Pin locale before the glob/sort so alias selection is deterministic. Two 
options worth the maintainer's judgment call rather than dictated here:

LC_ALL=C — simplest, guarantees determinism, but also forces C for LC_MESSAGES 
etc. for anything else evaluated in that scope, which could affect translated 
debconf prompt text if that scope is ever widened.
LC_COLLATE=C specifically — narrower, fixes only the sort/glob-ordering 
dependency without touching message localization, arguably the more surgical 
fix.

Separately worth considering: since downstream consumers of
install_devices (the disks-changed reconciliation logic later in the
same script) already compare entries by readlink -f realpath rather than
by string, would it be more robust for available_ids()/device_to_id() to
guarantee a canonical scheme preference (e.g. always prefer non-nvme-
eui.* names when multiple aliases exist) rather than relying on sort-
order-as-tiebreak at all? That would make the stored value locale-
independent by construction rather than by pinning locale at just this
one call site, and be more resilient if this dedup logic is ever copy-
pasted elsewhere without the pin.

** Description changed:

  grub-multi-install is not locale stable, which means, for systems with
  multiple ESPs, running:
  
  sudo LC_ALL=C dpkg-reconfigure grub-efi-arm64
  
  and
  
  sudo LC_ALL=en_US.UTF-8 dpkg-reconfigure grub-efi-arm64
  
  stores different output in grub-efi/install_devices, for example:
  
  with LC_ALL=C:
  * grub-efi/install_devices: 
/dev/disk/by-id/nvme-Micron_7450_MTFDKBA480TFR_254954CD71E8-part1, 
/dev/disk/by-id/nvme-Micron_7450_MTFDKBA480TFR_254954CD7CF6-part1
  
  with LC_ALL=en_US.UTF-8:
  * grub-efi/install_devices: 
/dev/disk/by-id/nvme-eui.000000000000000100a0752554cd71e8-part1, 
/dev/disk/by-id/nvme-eui.000000000000000100a0752554cd7cf6-part1
  
+ note that, options selected in LC_ALL=C are not checked in
+ LC_ALL=en_US.UTF-8, all the available ESP listed are unselected.
+ 
  ---
  
  This can cause issues that grub-efi/install_devices are overwritten with
  incorrect values when GRUB is upgraded and reinstalled with locales
  different from C

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2164992

Title:
  install_devices alias selection in grub-multi-install is not locale-
  stable, causing spurious reconfiguration across locales

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/2164992/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to