In addition to the prior patch to avoid leaving holes in the returned devicelist, the enumeration logic also needed fixing. GET_ARRAY_INFO's info.nr_disks does not map to GET_DISK_INFO's disk.number, which is an internal kernel index. If an array has had drives added, removed, etc, there may be gaps in GET_DISK_INFO's results. Instead, do what mdadm does and keep scanning until we find enough valid (major/minor != 0) disks.
Fixes: 2b00217369ac ("... Added support for RAID and LVM") Fixes: https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1912043 Fixes: https://savannah.gnu.org/bugs/index.php?59887 Signed-off-by: Kees Cook <k...@ubuntu.com> (This is intended to be applied on top of the earlier patch sent in https://lists.gnu.org/archive/html/grub-devel/2021-01/msg00027.html) Index: grub2-2.04/grub-core/osdep/linux/getroot.c =================================================================== --- grub2-2.04.orig/grub-core/osdep/linux/getroot.c +++ grub2-2.04/grub-core/osdep/linux/getroot.c @@ -135,10 +135,18 @@ struct mountinfo_entry char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1]; }; +/* GET_ARRAY_INFO's info.nr_disks does not map to GET_DISK_INFO's + disk.number, which is an internal kernel index. Instead, do what mdadm + does and keep scanning until we find enough valid disks. The limit is + copied from there, which notes that it is sufficiently high given + that the on-disk metadata for v1.x can only support 1920. */ +#define MD_MAX_DISKS 4096 + static char ** grub_util_raid_getmembers (const char *name, int bootable) { int fd, ret, i, j; + int remaining; char **devicelist; mdu_version_t version; mdu_array_info_t info; @@ -170,12 +178,17 @@ grub_util_raid_getmembers (const char *n devicelist = xcalloc (info.nr_disks + 1, sizeof (char *)); - for (i = 0, j = 0; i < info.nr_disks; i++) + remaining = info.nr_disks; + for (i = 0, j = 0; i < MD_MAX_DISKS && remaining > 0; i++) { disk.number = i; ret = ioctl (fd, GET_DISK_INFO, &disk); if (ret != 0) grub_util_error (_("ioctl GET_DISK_INFO error: %s"), strerror (errno)); + /* Skip empty disk slot. */ + if (disk.major == 0 && disk.minor == 0) + continue; + remaining--; if (disk.state & (1 << MD_DISK_REMOVED)) continue; -- Kees Cook @outflux.net _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel