tags 474931 patch
thanks

On Tue, Apr 08, 2008 at 02:20:25AM +0300, Sami Liedes wrote:
> (gdb) print q
> $2 = 0x66b5b4 " LVM2 x[5A%r0N*>\001"

This could mean that your LVM is corrupt, or that our LVM logic is incomplete.
Unfortunately I don't have the time to review that, but I improved the parser
to make it more robust, failing safely when problems like this one arise.  This
fixes the issue at hand (using grub-probe in update-grub).

Please, could you try the attached patch and report your results?

Thanks

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What use is a phone call… if you are unable to speak?
(as seen on /.)
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/disk/lvm.c ./disk/lvm.c
--- ../grub2/disk/lvm.c	2008-02-09 11:49:29.000000000 +0100
+++ ./disk/lvm.c	2008-04-10 10:06:00.000000000 +0200
@@ -29,11 +29,15 @@ static int lv_count;
 
 
 /* Go the string STR and return the number after STR.  *P will point
-   at the number. */
+   at the number.  In case STR is not found, *P will be NULL and the
+   return value will be 0.  */
 static int
 grub_lvm_getvalue (char **p, char *str)
 {
-  *p = grub_strstr (*p, str) + grub_strlen (str);
+  *p = grub_strstr (*p, str);
+  if (! *p)
+    return 0;
+  *p += grub_strlen (str);
   return grub_strtoul (*p, NULL, 10);
 }
 
@@ -44,6 +48,7 @@ grub_lvm_iterate (int (*hook) (const cha
   for (vg = vg_list; vg; vg = vg->next)
     {
       struct grub_lvm_lv *lv;
+if (vg->lvs)
       for (lv = vg->lvs; lv; lv = lv->next)
 	if (hook (lv->name))
 	  return 1;
@@ -60,6 +65,7 @@ grub_lvm_memberlist (grub_disk_t disk)
   grub_disk_memberlist_t list = NULL, tmp;
   struct grub_lvm_pv *pv;
 
+  if (lv->vg->pvs)
   for (pv = lv->vg->pvs; pv; pv = pv->next)
     {
       tmp = grub_malloc (sizeof (*tmp));
@@ -79,6 +85,7 @@ grub_lvm_open (const char *name, grub_di
   struct grub_lvm_lv *lv = NULL;
   for (vg = vg_list; vg; vg = vg->next)
     {
+if (vg->lvs)
       for (lv = vg->lvs; lv; lv = lv->next)
 	if (! grub_strcmp (lv->name, name))
 	  break;
@@ -330,14 +337,19 @@ grub_lvm_scan_device (const char *name)
       grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1);
 
       vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
+      if (p == NULL)
+	goto fail2;
 
       vg->lvs = NULL;
       vg->pvs = NULL;
       vg->next = vg_list;
       vg_list = vg;
 
-      p = grub_strstr (p, "physical_volumes {")
-	+ sizeof ("physical_volumes {") - 1;
+      p = grub_strstr (p, "physical_volumes {");
+      if (p)
+	{
+
+      p += sizeof ("physical_volumes {") - 1;
 
       /* Add all the pvs to the volume group. */
       while (1)
@@ -360,19 +372,33 @@ grub_lvm_scan_device (const char *name)
 	  pv->name[s] = '\0';
 
 	  p = grub_strstr (p, "id = \"") + sizeof("id = \"") - 1;
+	  if (p == NULL)
+	    goto pvs_fail;
 
 	  grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN);
 	  pv->id[GRUB_LVM_ID_STRLEN] = '\0';
 
 	  pv->start = grub_lvm_getvalue (&p, "pe_start = ");
+	  if (p == NULL)
+	    goto pvs_fail;
 	  pv->disk = NULL;
 	  pv->next = vg->pvs;
 	  vg->pvs = pv;
 
 	  p = grub_strchr (p, '}') + 1;
+
+	  continue;
+	pvs_fail:
+	  grub_free (pv->name);
+	  grub_free (pv);
+	  goto fail2;
+	}
+
 	}
 
       p = grub_strstr (p, "logical_volumes");
+if (p)
+{
       p += 18;
       
       /* And add all the lvs to the volume group. */
@@ -404,6 +430,8 @@ grub_lvm_scan_device (const char *name)
 	  lv->size = 0;
 	  
 	  lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
+	  if (p == NULL)
+	    goto lvs_fail;
 	  lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
 	  seg = lv->segments;
 
@@ -412,10 +440,18 @@ grub_lvm_scan_device (const char *name)
 	      struct grub_lvm_stripe *stripe;
 		
 	      p = grub_strstr (p, "segment");
+	      if (p == NULL)
+		goto lvs_segment_fail;
 
 	      seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
+	      if (p == NULL)
+		goto lvs_segment_fail;
 	      seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
+	      if (p == NULL)
+		goto lvs_segment_fail;
 	      seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = ");
+	      if (p == NULL)
+		goto lvs_segment_fail;
 
 	      lv->size += seg->extent_count * vg->extent_size;
 	      
@@ -426,14 +462,19 @@ grub_lvm_scan_device (const char *name)
 					  * seg->stripe_count);
 	      stripe = seg->stripes;
 	      
-	      p = grub_strstr (p, "stripes = [")
-		+ sizeof("stripes = [") - 1;
+	      p = grub_strstr (p, "stripes = [");
+	      if (p == NULL)
+		goto lvs_segment_fail2;
+	      p += sizeof("stripes = [") - 1;
 	      
 	      for (j = 0; j < seg->stripe_count; j++)
 		{
 		  char pvname[10];
 		  
-		  q = p = grub_strchr (p, '"') + 1;
+		  p = grub_strchr (p, '"');
+		  if (p == NULL)
+		    continue;
+		  q = ++p;
 		  while (*q != '"')
 		    q++;
 
@@ -441,6 +482,7 @@ grub_lvm_scan_device (const char *name)
 		  grub_memcpy (pvname, p, s);
 		  pvname[s] = '\0';
 		  
+		  if (vg->pvs)
 		  for (pv = vg->pvs; pv; pv = pv->next)
 		    {
 		      if (! grub_strcmp (pvname, pv->name))
@@ -450,13 +492,20 @@ grub_lvm_scan_device (const char *name)
 			}
 		    }
 
-		  p = grub_strchr (p, ',') + 1;
-		  stripe->start = grub_strtoul (p, NULL, 10);
+		  stripe->start = grub_lvm_getvalue (&p, ",");
+		  if (p == NULL)
+		    continue;
 		  
 		  stripe++;
 		}
 
 	      seg++;
+
+	      continue;
+	    lvs_segment_fail2:
+	      grub_free (seg->stripes);
+	    lvs_segment_fail:
+	      goto fail2;
 	    }
 
 	  lv->number = lv_count++;
@@ -464,8 +513,18 @@ grub_lvm_scan_device (const char *name)
 	  lv->next = vg->lvs;
 	  vg->lvs = lv;
 
-	  p = grub_strchr (p, '}') + 3;
+	  p = grub_strchr (p, '}');
+	  if (p == NULL)
+	    goto lvs_fail;
+	  p += 3;
+
+	  continue;
+	lvs_fail:
+	  grub_free (lv->name);
+	  grub_free (lv);
+	  goto fail2;
 	}
+}
     }
   else
     {
@@ -474,6 +533,7 @@ grub_lvm_scan_device (const char *name)
 
   /* Match the device we are currently reading from with the right
      PV. */
+  if (vg->pvs)
   for (pv = vg->pvs; pv; pv = pv->next)
     {
       if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN))

Reply via email to