Skip to contentSkip to conversation

Fix prefix autodetection when booting from EFI CD-ROM

PATCH In review Andrey Borzenkov 2 participants 5 messages Jan 31, 2013 – Oct 14, 2013

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Fix prefix autodetection when booting from EFI CD-ROM

Fix autodetection of $prefix when booted from EFI CD-ROM.

Based on patch from Matthew Garrett, modified to not overwrite memory returned by device path protocol handler and rebased to current trunk.

Additionally fixes potential memory leak - dup_dp was not deallocated if device path was not found.

---
 grub-core/disk/efi/efidisk.c |  121 +++++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 55 deletions(-)
grub-core/disk/efi/efidisk.c +66 -55
index 98cd226..15c8109 100644
@@ -775,67 +775,78 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
   if (! ldp)
     return 0;
 
-  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
-      && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
-	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
     {
-      struct grub_efidisk_get_device_name_ctx ctx;
-      char *dev_name;
-      grub_efi_device_path_t *dup_dp, *dup_ldp;
-      grub_disk_t parent = 0;
-
-      /* It is necessary to duplicate the device path so that GRUB
-	 can overwrite it.  */
-      dup_dp = duplicate_device_path (dp);
-      if (! dup_dp)
-	return 0;
-
-      dup_ldp = find_last_device_path (dup_dp);
-      dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-      dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-      dup_ldp->length[0] = sizeof (*dup_ldp);
-      dup_ldp->length[1] = 0;
+      int is_cdrom = 0;
 
-      if (!get_diskname_from_path (dup_dp, device_name))
-	return 0;
-      parent = grub_disk_open (device_name);
-      grub_free (dup_dp);
-
-      if (! parent)
-	return 0;
-
-      /* Find a partition which matches the hard drive device path.  */
-      ctx.partition_name = NULL;
-      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
-      if (ctx.hd.partition_start == 0
-	  && ctx.hd.partition_size == grub_disk_get_size (parent))
-	{
-	  dev_name = grub_strdup (parent->name);
-	}
-      else
+      switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp))
 	{
-	  grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
-				  &ctx);
-
-	  if (! ctx.partition_name)
+	  case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
+	    is_cdrom = 1;
+	    /* Intentionally fall through */
+	  case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
 	    {
+	      struct grub_efidisk_get_device_name_ctx ctx;
+	      char *dev_name;
+	      grub_efi_device_path_t *dup_dp, *dup_ldp;
+	      grub_disk_t parent = 0;
+
+	      /* It is necessary to duplicate the device path so that GRUB
+		 can overwrite it.  */
+	      dup_dp = duplicate_device_path (dp);
+	      if (! dup_dp)
+		return 0;
+
+	      dup_ldp = find_last_device_path (dup_dp);
+	      dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+	      dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+	      dup_ldp->length[0] = sizeof (*dup_ldp);
+	      dup_ldp->length[1] = 0;
+
+	      if (!get_diskname_from_path (dup_dp, device_name))
+		{
+		  grub_free (dup_dp);
+		  return 0;
+		}
+	      grub_free (dup_dp);
+	      if (is_cdrom)
+		return grub_strdup (device_name);
+
+	      parent = grub_disk_open (device_name);
+	      if (! parent)
+		return 0;
+
+	      /* Find a partition which matches the hard drive device path.  */
+	      ctx.partition_name = NULL;
+	      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
+	      if (ctx.hd.partition_start == 0
+		  && ctx.hd.partition_size == grub_disk_get_size (parent))
+		{
+		  dev_name = grub_strdup (parent->name);
+		}
+	      else
+		{
+		  grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
+					  &ctx);
+
+		  if (! ctx.partition_name)
+		    {
+		      grub_disk_close (parent);
+		      return 0;
+		    }
+
+		  dev_name = grub_xasprintf ("%s,%s", parent->name,
+					     ctx.partition_name);
+		  grub_free (ctx.partition_name);
+		}
 	      grub_disk_close (parent);
-	      return 0;
-	    }
 
-	  dev_name = grub_xasprintf ("%s,%s", parent->name,
-				     ctx.partition_name);
-	  grub_free (ctx.partition_name);
+	      return dev_name;
+	    }
 	}
-      grub_disk_close (parent);
-
-      return dev_name;
-    }
-  else
-    {
-      /* This should be an entire disk.  */
-      if (!get_diskname_from_path (dp, device_name))
-	return 0;
-      return grub_strdup (device_name);
     }
+  /* This may be guessed device - floppy, cdrom or entire disk.  */
+  if (!get_diskname_from_path (dp, device_name))
+    return 0;
+  return grub_strdup (device_name);
 }
Signature · 1 line
tg: (4b9ea2e..) u/efi-cdrom-prefix (depends on: master)
#1 lore raw
Quoted 5 lines · Andrey Borzenkov

Fix autodetection of $prefix when booted from EFI CD-ROM.

Based on patch from Matthew Garrett, modified to not overwrite memory returned by device path protocol handler and rebased to current trunk.

Due to legal issues we need Matthew Garrett, or someone from Red Hat, to send the patch. I wonder why this didn't happen before.

Quoted 148 lines

Additionally fixes potential memory leak - dup_dp was not deallocated if device path was not found.

---
 grub-core/disk/efi/efidisk.c |  121 +++++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 55 deletions(-)
grub-core/disk/efi/efidisk.c +66 -55
index 98cd226..15c8109 100644
@@ -775,67 +775,78 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
   if (! ldp)
     return 0;
 
-  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
-      && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
-	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
     {
-      struct grub_efidisk_get_device_name_ctx ctx;
-      char *dev_name;
-      grub_efi_device_path_t *dup_dp, *dup_ldp;
-      grub_disk_t parent = 0;
-
-      /* It is necessary to duplicate the device path so that GRUB
-	 can overwrite it.  */
-      dup_dp = duplicate_device_path (dp);
-      if (! dup_dp)
-	return 0;
-
-      dup_ldp = find_last_device_path (dup_dp);
-      dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-      dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-      dup_ldp->length[0] = sizeof (*dup_ldp);
-      dup_ldp->length[1] = 0;
+      int is_cdrom = 0;
 
-      if (!get_diskname_from_path (dup_dp, device_name))
-	return 0;
-      parent = grub_disk_open (device_name);
-      grub_free (dup_dp);
-
-      if (! parent)
-	return 0;
-
-      /* Find a partition which matches the hard drive device path.  */
-      ctx.partition_name = NULL;
-      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
-      if (ctx.hd.partition_start == 0
-	  && ctx.hd.partition_size == grub_disk_get_size (parent))
-	{
-	  dev_name = grub_strdup (parent->name);
-	}
-      else
+      switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp))
 	{
-	  grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
-				  &ctx);
-
-	  if (! ctx.partition_name)
+	  case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
+	    is_cdrom = 1;
+	    /* Intentionally fall through */
+	  case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
 	    {
+	      struct grub_efidisk_get_device_name_ctx ctx;
+	      char *dev_name;
+	      grub_efi_device_path_t *dup_dp, *dup_ldp;
+	      grub_disk_t parent = 0;
+
+	      /* It is necessary to duplicate the device path so that GRUB
+		 can overwrite it.  */
+	      dup_dp = duplicate_device_path (dp);
+	      if (! dup_dp)
+		return 0;
+
+	      dup_ldp = find_last_device_path (dup_dp);
+	      dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+	      dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+	      dup_ldp->length[0] = sizeof (*dup_ldp);
+	      dup_ldp->length[1] = 0;
+
+	      if (!get_diskname_from_path (dup_dp, device_name))
+		{
+		  grub_free (dup_dp);
+		  return 0;
+		}
+	      grub_free (dup_dp);
+	      if (is_cdrom)
+		return grub_strdup (device_name);
+
+	      parent = grub_disk_open (device_name);
+	      if (! parent)
+		return 0;
+
+	      /* Find a partition which matches the hard drive device path.  */
+	      ctx.partition_name = NULL;
+	      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
+	      if (ctx.hd.partition_start == 0
+		  && ctx.hd.partition_size == grub_disk_get_size (parent))
+		{
+		  dev_name = grub_strdup (parent->name);
+		}
+	      else
+		{
+		  grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
+					  &ctx);
+
+		  if (! ctx.partition_name)
+		    {
+		      grub_disk_close (parent);
+		      return 0;
+		    }
+
+		  dev_name = grub_xasprintf ("%s,%s", parent->name,
+					     ctx.partition_name);
+		  grub_free (ctx.partition_name);
+		}
 	      grub_disk_close (parent);
-	      return 0;
-	    }
 
-	  dev_name = grub_xasprintf ("%s,%s", parent->name,
-				     ctx.partition_name);
-	  grub_free (ctx.partition_name);
+	      return dev_name;
+	    }
 	}
-      grub_disk_close (parent);
-
-      return dev_name;
-    }
-  else
-    {
-      /* This should be an entire disk.  */
-      if (!get_diskname_from_path (dp, device_name))
-	return 0;
-      return grub_strdup (device_name);
     }
+  /* This may be guessed device - floppy, cdrom or entire disk.  */
+  if (!get_diskname_from_path (dp, device_name))
+    return 0;
+  return grub_strdup (device_name);
 }
Signature · 2 lines
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
#2 lore raw
In reply to Andrey Borzenkov
Quoted 8 lines · Andrey Borzenkov

Fix autodetection of $prefix when booted from EFI CD-ROM.

Based on patch from Matthew Garrett, modified to not overwrite memory returned by device path protocol handler and rebased to current trunk.

Additionally fixes potential memory leak - dup_dp was not deallocated if device path was not found.

Why any special treatement for CD-ROMs? They can have partitions and do so on CD-ROMs intended for macs. What about following patch:

[email protected]:15:02:18:~/grub2/bzr/mainline$ bzr diff
=== modified file 'grub-core/disk/efi/efidisk.c'
--- grub-core/disk/efi/efidisk.c	2013-04-05 08:59:26 +0000
+++ grub-core/disk/efi/efidisk.c	2013-04-05 13:07:39 +0000
@@ -633,9 +633,6 @@
       return d->handle;
     case 'c':
-      /* FIXME: probably this is not correct.  */
-      return d->handle;
-
     case 'h':
       /* If this is the whole disk, just return its own data.  */
       if (! disk->partition)

@@ -657,7 +654,9 @@
if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
== GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)

-		    == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
+		    == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE
+		    || GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
+		    == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE)

&& (grub_partition_get_start (disk->partition)
== (hd.partition_start << (disk->log_sector_size
- GRUB_DISK_SECTOR_BITS)))
@@ -770,7 +769,9 @@

if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE

       && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
-	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
+	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE
+	  || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
+	  == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE))
     {
       struct grub_efidisk_get_device_name_ctx ctx;
       char *dev_name;
#3 lore raw

В Fri, 05 Apr 2013 15:12:26 +0200
Vladimir 'φ-coder/phcoder' Serbinenko <[email protected]> пишет:

Quoted 8 lines · Andrey Borzenkov
Quoted 7 lines

Fix autodetection of $prefix when booted from EFI CD-ROM.

Based on patch from Matthew Garrett, modified to not overwrite memory returned by device path protocol handler and rebased to current trunk.

Quoted 6 lines
Quoted 2 lines

Additionally fixes potential memory leak - dup_dp was not deallocated if device path was not found.

Why any special treatement for CD-ROMs? They can have partitions and do so on CD-ROMs intended for macs. What about following patch:

CD-ROM media device path in UEFI is defined for a single boot catalog entry - EFI system partition. EFI will *always* return this when booted from CD. But we do *not* want this "partition" - we want full CD access here. This ESP image normally exists just to load grub off it. Everything else is part of normal ISO on CD-ROM.

Also there is no partition label that can be detected and points to this boot catalog entry; so partition matching code will simply fail.

So we want a) skip partition search based on media device subpath and
b) strip media device subpath.

I'm not sure what partitions on MAC are but I suspect they are not boot catalog entries.

Quoted 39 lines
[email protected]:15:02:18:~/grub2/bzr/mainline$ bzr diff
=== modified file 'grub-core/disk/efi/efidisk.c'
disk/efi/efidisk.c +6 -5
@@ -633,9 +633,6 @@
       return d->handle;
 
     case 'c':
-      /* FIXME: probably this is not correct.  */
-      return d->handle;
-
     case 'h':
       /* If this is the whole disk, just return its own data.  */
       if (! disk->partition)
@@ -657,7 +654,9 @@
 	    if ((GRUB_EFI_DEVICE_PATH_TYPE (c->last_device_path)
 		 == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
 		&& (GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
-		    == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE)
+		    == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE
+		    || GRUB_EFI_DEVICE_PATH_SUBTYPE (c->last_device_path)
+		    == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE)
 		&& (grub_partition_get_start (disk->partition)
 		    == (hd.partition_start << (disk->log_sector_size
 					       - GRUB_DISK_SECTOR_BITS)))
@@ -770,7 +769,9 @@
 
   if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
       && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
-	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
+	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE
+	  || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
+	  == GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE))
     {
       struct grub_efidisk_get_device_name_ctx ctx;
       char *dev_name;
#4 lore raw
In reply to Andrey Borzenkov

Committed with a change to handle Apple HFS+ boot (return full disk only if no matching partition is found).
Thanks.

Quoted 154 lines · Andrey Borzenkov

Fix autodetection of $prefix when booted from EFI CD-ROM.

Based on patch from Matthew Garrett, modified to not overwrite memory returned by device path protocol handler and rebased to current trunk.

Additionally fixes potential memory leak - dup_dp was not deallocated if device path was not found.

---
 grub-core/disk/efi/efidisk.c |  121 +++++++++++++++++++++++-------------------
 1 file changed, 66 insertions(+), 55 deletions(-)
grub-core/disk/efi/efidisk.c +66 -55
index 98cd226..15c8109 100644
@@ -775,67 +775,78 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle)
   if (! ldp)
     return 0;
 
-  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE
-      && (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp)
-	  == GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE))
+  if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE)
     {
-      struct grub_efidisk_get_device_name_ctx ctx;
-      char *dev_name;
-      grub_efi_device_path_t *dup_dp, *dup_ldp;
-      grub_disk_t parent = 0;
-
-      /* It is necessary to duplicate the device path so that GRUB
-	 can overwrite it.  */
-      dup_dp = duplicate_device_path (dp);
-      if (! dup_dp)
-	return 0;
-
-      dup_ldp = find_last_device_path (dup_dp);
-      dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
-      dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
-      dup_ldp->length[0] = sizeof (*dup_ldp);
-      dup_ldp->length[1] = 0;
+      int is_cdrom = 0;
 
-      if (!get_diskname_from_path (dup_dp, device_name))
-	return 0;
-      parent = grub_disk_open (device_name);
-      grub_free (dup_dp);
-
-      if (! parent)
-	return 0;
-
-      /* Find a partition which matches the hard drive device path.  */
-      ctx.partition_name = NULL;
-      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
-      if (ctx.hd.partition_start == 0
-	  && ctx.hd.partition_size == grub_disk_get_size (parent))
-	{
-	  dev_name = grub_strdup (parent->name);
-	}
-      else
+      switch (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp))
 	{
-	  grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
-				  &ctx);
-
-	  if (! ctx.partition_name)
+	  case GRUB_EFI_CDROM_DEVICE_PATH_SUBTYPE:
+	    is_cdrom = 1;
+	    /* Intentionally fall through */
+	  case GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE:
 	    {
+	      struct grub_efidisk_get_device_name_ctx ctx;
+	      char *dev_name;
+	      grub_efi_device_path_t *dup_dp, *dup_ldp;
+	      grub_disk_t parent = 0;
+
+	      /* It is necessary to duplicate the device path so that GRUB
+		 can overwrite it.  */
+	      dup_dp = duplicate_device_path (dp);
+	      if (! dup_dp)
+		return 0;
+
+	      dup_ldp = find_last_device_path (dup_dp);
+	      dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+	      dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+	      dup_ldp->length[0] = sizeof (*dup_ldp);
+	      dup_ldp->length[1] = 0;
+
+	      if (!get_diskname_from_path (dup_dp, device_name))
+		{
+		  grub_free (dup_dp);
+		  return 0;
+		}
+	      grub_free (dup_dp);
+	      if (is_cdrom)
+		return grub_strdup (device_name);
+
+	      parent = grub_disk_open (device_name);
+	      if (! parent)
+		return 0;
+
+	      /* Find a partition which matches the hard drive device path.  */
+	      ctx.partition_name = NULL;
+	      grub_memcpy (&ctx.hd, ldp, sizeof (ctx.hd));
+	      if (ctx.hd.partition_start == 0
+		  && ctx.hd.partition_size == grub_disk_get_size (parent))
+		{
+		  dev_name = grub_strdup (parent->name);
+		}
+	      else
+		{
+		  grub_partition_iterate (parent, grub_efidisk_get_device_name_iter,
+					  &ctx);
+
+		  if (! ctx.partition_name)
+		    {
+		      grub_disk_close (parent);
+		      return 0;
+		    }
+
+		  dev_name = grub_xasprintf ("%s,%s", parent->name,
+					     ctx.partition_name);
+		  grub_free (ctx.partition_name);
+		}
 	      grub_disk_close (parent);
-	      return 0;
-	    }
 
-	  dev_name = grub_xasprintf ("%s,%s", parent->name,
-				     ctx.partition_name);
-	  grub_free (ctx.partition_name);
+	      return dev_name;
+	    }
 	}
-      grub_disk_close (parent);
-
-      return dev_name;
-    }
-  else
-    {
-      /* This should be an entire disk.  */
-      if (!get_diskname_from_path (dp, device_name))
-	return 0;
-      return grub_strdup (device_name);
     }
+  /* This may be guessed device - floppy, cdrom or entire disk.  */
+  if (!get_diskname_from_path (dp, device_name))
+    return 0;
+  return grub_strdup (device_name);
 }