From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Thu, 21 Jan 2021 18:35:22 +1100
Subject: [PATCH] disk/lvm: Do not overread metadata

We could reach the end of valid metadata and not realize, leading to
some buffer overreads. Check if we have reached the end and bail.

Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 grub-core/disk/lvm.c | 31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
index 03587e744dc..267be7b9536 100644
--- a/grub-core/disk/lvm.c
+++ b/grub-core/disk/lvm.c
@@ -314,17 +314,23 @@ error_parsing_metadata:
 	  while (1)
 	    {
 	      grub_ssize_t s;
-	      while (grub_isspace (*p))
+	      while (grub_isspace (*p) && p < mda_end)
 		p++;
 
+	      if (p == mda_end)
+		goto fail4;
+
 	      if (*p == '}')
 		break;
 
 	      pv = grub_zalloc (sizeof (*pv));
 	      q = p;
-	      while (*q != ' ')
+	      while (*q != ' ' && q < mda_end)
 		q++;
 
+	      if (q == mda_end)
+		goto pvs_fail_noname;
+
 	      s = q - p;
 	      pv->name = grub_malloc (s + 1);
 	      grub_memcpy (pv->name, p, s);
@@ -367,6 +373,7 @@ error_parsing_metadata:
 	      continue;
 	    pvs_fail:
 	      grub_free (pv->name);
+	    pvs_fail_noname:
 	      grub_free (pv);
 	      goto fail4;
 	    }
@@ -388,18 +395,24 @@ error_parsing_metadata:
 	      struct grub_diskfilter_segment *seg;
 	      int is_pvmove;
 
-	      while (grub_isspace (*p))
+	      while (grub_isspace (*p) && p < mda_end)
 		p++;
 
+	      if (p == mda_end)
+		goto fail4;
+
 	      if (*p == '}')
 		break;
 
 	      lv = grub_zalloc (sizeof (*lv));
 
 	      q = p;
-	      while (*q != ' ')
+	      while (*q != ' ' && q < mda_end)
 		q++;
 
+	      if (q == mda_end)
+		goto lvs_fail;
+
 	      s = q - p;
 	      lv->name = grub_strndup (p, s);
 	      if (!lv->name)
@@ -572,9 +585,12 @@ error_parsing_metadata:
 			  if (p == NULL)
 			    goto lvs_segment_fail2;
 			  q = ++p;
-			  while (*q != '"')
+			  while (q < mda_end && *q != '"')
 			    q++;
 
+			  if (q == mda_end)
+			    goto lvs_segment_fail2;
+
 			  s = q - p;
 
 			  stripe->name = grub_malloc (s + 1);
@@ -631,9 +647,12 @@ error_parsing_metadata:
 			  if (p == NULL)
 			    goto lvs_segment_fail2;
 			  q = ++p;
-			  while (*q != '"')
+			  while (q < mda_end && *q != '"')
 			    q++;
 
+			  if (q == mda_end)
+			    goto lvs_segment_fail2;
+
 			  s = q - p;
 
 			  lvname = grub_malloc (s + 1);
