I'm unsure whether an id starting with a numeral should be considered valid
at all. Variable named 0x would be incorrect

Le lun. 22 avr. 2024, 17:57, Marek Marczykowski-Górecki <
marma...@invisiblethingslab.com> a écrit :

> From: Peter Jones <pjo...@redhat.com>
>
> Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an
> error, we assume the value it has produced is a correct index into our
> menu entry list, and do not try to interpret the value as the "id" or
> "title" .  In cases where "id" or "title" start with a numeral, this
> makes them impossible to use as selection criteria.
>
> This patch splits the search into three phases - matching id, matching
> title, and only once those have been exhausted, trying to interpret the
> ID as a numeral.  In that case, we also require that the entire string
> is numeric, not merely a string with leading numeric characters.
>
> Resolves: rhbz#1640979
>
> Signed-off-by: Peter Jones <pjo...@redhat.com>
> [javierm: fix menu entry selection based on title]
> Signed-off-by: Javier Martinez Canillas <javi...@redhat.com>
> ---
>  grub-core/normal/menu.c | 141 ++++++++++++++++++++---------------------
>  1 file changed, 71 insertions(+), 70 deletions(-)
>
> diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
> index 6444ee6..b0cfa32 100644
> --- a/grub-core/normal/menu.c
> +++ b/grub-core/normal/menu.c
> @@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout)
>  }
>
>  static int
> -menuentry_eq (const char *id, const char *spec)
> +menuentry_eq (const char *id, const char *spec, int limit)
>  {
>    const char *ptr1, *ptr2;
>    ptr1 = id;
>    ptr2 = spec;
> -  while (1)
> +  while (limit == -1 || ptr1 - id <= limit)
>      {
>        if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0)
>         return ptr2 - spec;
> @@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec)
>        if (*ptr2 == '>')
>         ptr2++;
>        if (*ptr1 != *ptr2)
> -       return 0;
> +       {
> +         if (limit > -1 && ptr1 - id == limit && !*ptr1 &&
> grub_isspace(*ptr2))
> +           return ptr1 -id -1;
> +         return 0;
> +       }
>        if (*ptr1 == 0)
>         return ptr1 - id;
>        ptr1++;
> @@ -187,6 +191,58 @@ menuentry_eq (const char *id, const char *spec)
>    return 0;
>  }
>
> +static int
> +get_entry_number_helper(grub_menu_t menu,
> +                       const char * const val, const char ** const tail)
> +{
> +  /* See if the variable matches the title of a menu entry.  */
> +  int entry = -1;
> +  grub_menu_entry_t e;
> +  int i;
> +
> +  for (i = 0, e = menu->entry_list; e; i++)
> +    {
> +      int l = 0;
> +      while (val[l] && !grub_isspace(val[l]))
> +       l++;
> +
> +      if (menuentry_eq (e->id, val, l))
> +       {
> +         if (tail)
> +           *tail = val + l;
> +         return i;
> +       }
> +      e = e->next;
> +    }
> +
> +  for (i = 0, e = menu->entry_list; e; i++)
> +    {
> +
> +      if (menuentry_eq (e->title, val, -1))
> +       {
> +         if (tail)
> +           *tail = NULL;
> +         return i;
> +       }
> +      e = e->next;
> +    }
> +
> +  if (tail)
> +    *tail = NULL;
> +
> +  entry = (int) grub_strtoul (val, tail, 0);
> +  if (grub_errno == GRUB_ERR_BAD_NUMBER ||
> +      (*tail && **tail && !grub_isspace(**tail)))
> +    {
> +      entry = -1;
> +      if (tail)
> +       *tail = NULL;
> +      grub_errno = GRUB_ERR_NONE;
> +    }
> +
> +  return entry;
> +}
> +
>  /* Get the first entry number from the value of the environment variable
> NAME,
>     which is a space-separated list of non-negative integers.  The entry
> number
>     which is returned is stripped from the value of NAME.  If no entry
> number
> @@ -196,7 +252,6 @@ get_and_remove_first_entry_number (grub_menu_t menu,
> const char *name)
>  {
>    const char *val, *tail;
>    int entry;
> -  int sz = 0;
>
>    val = grub_env_get (name);
>    if (! val)
> @@ -204,50 +259,24 @@ get_and_remove_first_entry_number (grub_menu_t menu,
> const char *name)
>
>    grub_error_push ();
>
> -  entry = (int) grub_strtoul (val, &tail, 0);
> -
> -  if (grub_errno == GRUB_ERR_BAD_NUMBER)
> -    {
> -      /* See if the variable matches the title of a menu entry.  */
> -      grub_menu_entry_t e = menu->entry_list;
> -      int i;
> -
> -      for (i = 0; e; i++)
> -       {
> -         sz = menuentry_eq (e->title, val);
> -         if (sz < 1)
> -           sz = menuentry_eq (e->id, val);
> -
> -         if (sz >= 1)
> -           {
> -             entry = i;
> -             break;
> -           }
> -         e = e->next;
> -       }
> +  entry = get_entry_number_helper(menu, val, &tail);
> +  if (!(*tail == 0 || grub_isspace(*tail)))
> +    entry = -1;
>
> -      if (sz > 0)
> -       grub_errno = GRUB_ERR_NONE;
> -
> -      if (! e)
> -       entry = -1;
> -    }
> -
> -  if (grub_errno == GRUB_ERR_NONE)
> +  if (entry >= 0)
>      {
> -      if (sz > 0)
> -       tail += sz;
> -
>        /* Skip whitespace to find the next entry.  */
>        while (*tail && grub_isspace (*tail))
>         tail++;
> -      grub_env_set (name, tail);
> +      if (*tail)
> +       grub_env_set (name, tail);
> +      else
> +       grub_env_unset (name);
>      }
>    else
>      {
>        grub_env_unset (name);
>        grub_errno = GRUB_ERR_NONE;
> -      entry = -1;
>      }
>
>    grub_error_pop ();
> @@ -524,6 +553,7 @@ static int
>  get_entry_number (grub_menu_t menu, const char *name)
>  {
>    const char *val;
> +  const char *tail;
>    int entry;
>
>    val = grub_env_get (name);
> @@ -531,38 +561,9 @@ get_entry_number (grub_menu_t menu, const char *name)
>      return -1;
>
>    grub_error_push ();
> -
> -  entry = (int) grub_strtoul (val, 0, 0);
> -
> -  if (grub_errno == GRUB_ERR_BAD_NUMBER)
> -    {
> -      /* See if the variable matches the title of a menu entry.  */
> -      grub_menu_entry_t e = menu->entry_list;
> -      int i;
> -
> -      grub_errno = GRUB_ERR_NONE;
> -
> -      for (i = 0; e; i++)
> -       {
> -         if (menuentry_eq (e->title, val)
> -             || menuentry_eq (e->id, val))
> -           {
> -             entry = i;
> -             break;
> -           }
> -         e = e->next;
> -       }
> -
> -      if (! e)
> -       entry = -1;
> -    }
> -
> -  if (grub_errno != GRUB_ERR_NONE)
> -    {
> -      grub_errno = GRUB_ERR_NONE;
> -      entry = -1;
> -    }
> -
> +  entry = get_entry_number_helper(menu, val, &tail);
> +  if (tail && *tail != '\0')
> +    entry = -1;
>    grub_error_pop ();
>
>    return entry;
> --
> git-series 0.9.1
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to