dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

Blame SOURCES/0246-Fix-menu-entry-selection-based-on-ID-and-title.patch

d9d99f
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
d9d99f
From: Peter Jones <pjones@redhat.com>
d9d99f
Date: Fri, 19 Oct 2018 10:57:52 -0400
d9d99f
Subject: [PATCH] Fix menu entry selection based on ID and title
d9d99f
d9d99f
Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an
d9d99f
error, we assume the value it has produced is a correct index into our
d9d99f
menu entry list, and do not try to interpret the value as the "id" or
d9d99f
"title" .  In cases where "id" or "title" start with a numeral, this
d9d99f
makes them impossible to use as selection criteria.
d9d99f
d9d99f
This patch splits the search into three phases - matching id, matching
d9d99f
title, and only once those have been exhausted, trying to interpret the
d9d99f
ID as a numeral.  In that case, we also require that the entire string
d9d99f
is numeric, not merely a string with leading numeric characters.
d9d99f
d9d99f
Resolves: rhbz#1640979
d9d99f
---
d9d99f
 grub-core/normal/menu.c | 146 +++++++++++++++++++++++++-----------------------
d9d99f
 1 file changed, 75 insertions(+), 71 deletions(-)
d9d99f
d9d99f
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
d9d99f
index 6cb2a071490..95f7abaf2fd 100644
d9d99f
--- a/grub-core/normal/menu.c
d9d99f
+++ b/grub-core/normal/menu.c
d9d99f
@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout)
d9d99f
 }
d9d99f
 
d9d99f
 static int
d9d99f
-menuentry_eq (const char *id, const char *spec)
d9d99f
+menuentry_eq (const char *id, const char *spec, int limit)
d9d99f
 {
d9d99f
   const char *ptr1, *ptr2;
d9d99f
   ptr1 = id;
d9d99f
   ptr2 = spec;
d9d99f
-  while (1)
d9d99f
+  while (limit == -1 || ptr1 - id <= limit)
d9d99f
     {
d9d99f
       if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
d9d99f
 	return ptr2 - spec;
d9d99f
@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec)
d9d99f
       if (*ptr2 == '>')
d9d99f
 	ptr2++;
d9d99f
       if (*ptr1 != *ptr2)
d9d99f
-	return 0;
d9d99f
+	{
d9d99f
+	  if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2))
d9d99f
+	    return ptr1 -id -1;
d9d99f
+	  return 0;
d9d99f
+	}
d9d99f
       if (*ptr1 == 0)
d9d99f
 	return ptr1 - id;
d9d99f
       ptr1++;
d9d99f
@@ -187,6 +191,61 @@ menuentry_eq (const char *id, const char *spec)
d9d99f
   return 0;
d9d99f
 }
d9d99f
 
d9d99f
+static int
d9d99f
+get_entry_number_helper(grub_menu_t menu,
d9d99f
+			const char * const val, const char ** const tail)
d9d99f
+{
d9d99f
+  /* See if the variable matches the title of a menu entry.  */
d9d99f
+  int entry = -1;
d9d99f
+  grub_menu_entry_t e;
d9d99f
+  int i;
d9d99f
+
d9d99f
+  for (i = 0, e = menu->entry_list; e; i++)
d9d99f
+    {
d9d99f
+      int l = 0;
d9d99f
+      while (val[l] && !grub_isspace(val[l]))
d9d99f
+	l++;
d9d99f
+
d9d99f
+      if (menuentry_eq (e->id, val, l))
d9d99f
+	{
d9d99f
+	  if (tail)
d9d99f
+	    *tail = val + l;
d9d99f
+	  return i;
d9d99f
+	}
d9d99f
+      e = e->next;
d9d99f
+    }
d9d99f
+
d9d99f
+  for (i = 0, e = menu->entry_list; e; i++)
d9d99f
+    {
d9d99f
+      int l = 0;
d9d99f
+      while (val[l] && !grub_isspace(val[l]))
d9d99f
+	l++;
d9d99f
+
d9d99f
+      if (menuentry_eq (e->title, val, l))
d9d99f
+	{
d9d99f
+	  if (tail)
d9d99f
+	    *tail = val + l;
d9d99f
+	  return i;
d9d99f
+	}
d9d99f
+      e = e->next;
d9d99f
+    }
d9d99f
+
d9d99f
+  if (tail)
d9d99f
+    *tail = NULL;
d9d99f
+
d9d99f
+  entry = (int) grub_strtoul (val, tail, 0);
d9d99f
+  if (grub_errno == GRUB_ERR_BAD_NUMBER ||
d9d99f
+      (*tail && **tail && !grub_isspace(**tail)))
d9d99f
+    {
d9d99f
+      entry = -1;
d9d99f
+      if (tail)
d9d99f
+	*tail = NULL;
d9d99f
+      grub_errno = GRUB_ERR_NONE;
d9d99f
+    }
d9d99f
+
d9d99f
+  return entry;
d9d99f
+}
d9d99f
+
d9d99f
 /* Get the first entry number from the value of the environment variable NAME,
d9d99f
    which is a space-separated list of non-negative integers.  The entry number
d9d99f
    which is returned is stripped from the value of NAME.  If no entry number
d9d99f
@@ -195,9 +254,8 @@ static int
d9d99f
 get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
d9d99f
 {
d9d99f
   const char *val;
d9d99f
-  char *tail;
d9d99f
+  const char *tail;
d9d99f
   int entry;
d9d99f
-  int sz = 0;
d9d99f
 
d9d99f
   val = grub_env_get (name);
d9d99f
   if (! val)
d9d99f
@@ -205,50 +263,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name)
d9d99f
 
d9d99f
   grub_error_push ();
d9d99f
 
d9d99f
-  entry = (int) grub_strtoul (val, &tail, 0);
d9d99f
+  entry = get_entry_number_helper(menu, val, &tail);
d9d99f
+  if (!(*tail == 0 || grub_isspace(*tail)))
d9d99f
+    entry = -1;
d9d99f
 
d9d99f
-  if (grub_errno == GRUB_ERR_BAD_NUMBER)
d9d99f
+  if (entry >= 0)
d9d99f
     {
d9d99f
-      /* See if the variable matches the title of a menu entry.  */
d9d99f
-      grub_menu_entry_t e = menu->entry_list;
d9d99f
-      int i;
d9d99f
-
d9d99f
-      for (i = 0; e; i++)
d9d99f
-	{
d9d99f
-	  sz = menuentry_eq (e->title, val);
d9d99f
-	  if (sz < 1)
d9d99f
-	    sz = menuentry_eq (e->id, val);
d9d99f
-
d9d99f
-	  if (sz >= 1)
d9d99f
-	    {
d9d99f
-	      entry = i;
d9d99f
-	      break;
d9d99f
-	    }
d9d99f
-	  e = e->next;
d9d99f
-	}
d9d99f
-
d9d99f
-      if (sz > 0)
d9d99f
-	grub_errno = GRUB_ERR_NONE;
d9d99f
-
d9d99f
-      if (! e)
d9d99f
-	entry = -1;
d9d99f
-    }
d9d99f
-
d9d99f
-  if (grub_errno == GRUB_ERR_NONE)
d9d99f
-    {
d9d99f
-      if (sz > 0)
d9d99f
-	tail += sz;
d9d99f
-
d9d99f
       /* Skip whitespace to find the next entry.  */
d9d99f
       while (*tail && grub_isspace (*tail))
d9d99f
 	tail++;
d9d99f
-      grub_env_set (name, tail);
d9d99f
+      if (*tail)
d9d99f
+	grub_env_set (name, tail);
d9d99f
+      else
d9d99f
+	grub_env_unset (name);
d9d99f
     }
d9d99f
   else
d9d99f
     {
d9d99f
       grub_env_unset (name);
d9d99f
       grub_errno = GRUB_ERR_NONE;
d9d99f
-      entry = -1;
d9d99f
     }
d9d99f
 
d9d99f
   grub_error_pop ();
d9d99f
@@ -525,6 +557,7 @@ static int
d9d99f
 get_entry_number (grub_menu_t menu, const char *name)
d9d99f
 {
d9d99f
   const char *val;
d9d99f
+  const char *tail;
d9d99f
   int entry;
d9d99f
 
d9d99f
   val = grub_env_get (name);
d9d99f
@@ -532,38 +565,9 @@ get_entry_number (grub_menu_t menu, const char *name)
d9d99f
     return -1;
d9d99f
 
d9d99f
   grub_error_push ();
d9d99f
-
d9d99f
-  entry = (int) grub_strtoul (val, 0, 0);
d9d99f
-
d9d99f
-  if (grub_errno == GRUB_ERR_BAD_NUMBER)
d9d99f
-    {
d9d99f
-      /* See if the variable matches the title of a menu entry.  */
d9d99f
-      grub_menu_entry_t e = menu->entry_list;
d9d99f
-      int i;
d9d99f
-
d9d99f
-      grub_errno = GRUB_ERR_NONE;
d9d99f
-
d9d99f
-      for (i = 0; e; i++)
d9d99f
-	{
d9d99f
-	  if (menuentry_eq (e->title, val)
d9d99f
-	      || menuentry_eq (e->id, val))
d9d99f
-	    {
d9d99f
-	      entry = i;
d9d99f
-	      break;
d9d99f
-	    }
d9d99f
-	  e = e->next;
d9d99f
-	}
d9d99f
-
d9d99f
-      if (! e)
d9d99f
-	entry = -1;
d9d99f
-    }
d9d99f
-
d9d99f
-  if (grub_errno != GRUB_ERR_NONE)
d9d99f
-    {
d9d99f
-      grub_errno = GRUB_ERR_NONE;
d9d99f
-      entry = -1;
d9d99f
-    }
d9d99f
-
d9d99f
+  entry = get_entry_number_helper(menu, val, &tail);
d9d99f
+  if (*tail != '\0')
d9d99f
+    entry = -1;
d9d99f
   grub_error_pop ();
d9d99f
 
d9d99f
   return entry;