Blob Blame History Raw
From 20ce60f211cef5f2c553130ba24b049381915252 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 1 Oct 2012 13:24:37 -0400
Subject: [PATCH] Handle "\x[[:hex:]][[:hex:]]" style escapes as well.

Sometimes we need to escape spaces and such in the config file, and we
do so by passing them in hex.
---
 grub-core/commands/wildcard.c | 26 +++++++++++++++++++-
 grub-core/lib/cmdline.c       | 44 ++++++++++++++++++++++++++++++++--
 grub-core/script/execute.c    | 55 ++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 116 insertions(+), 9 deletions(-)

diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c
index 2b73d9a..8ea76c9 100644
--- a/grub-core/commands/wildcard.c
+++ b/grub-core/commands/wildcard.c
@@ -420,6 +420,23 @@ check_file (const char *dir, const char *basename)
   return found;
 }
 
+static int
+is_hex(char c)
+{
+  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
+static grub_int32_t
+hex_to_int(char c)
+{
+  int i = c | 0x20;
+  if (i >= '0' && i < '9')
+    return i - '0';
+  if (i >= 'a' && i < 'f')
+    return i - ('a' - 10);
+  return -1;
+}
+
 static void
 unescape (char *out, const char *in, const char *end)
 {
@@ -428,7 +445,14 @@ unescape (char *out, const char *in, const char *end)
 
   for (optr = out, iptr = in; iptr < end;)
     {
-      if (*iptr == '\\' && iptr + 1 < end)
+      if (*iptr == '\\' && iptr + 3 < end && iptr[1] == 'x' && is_hex(iptr[2]) && is_hex(iptr[3]))
+	{
+	  int a = (hex_to_int(iptr[2]) << 4) | (hex_to_int(iptr[3]) & 0xf);
+	  *optr++ = a & 0xff;
+	  iptr += 4;
+	  continue;
+	}
+      else if (*iptr == '\\' && iptr + 1 < end)
 	{
 	  *optr++ = iptr[1];
 	  iptr += 2;
diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
index a702e64..78a96fa 100644
--- a/grub-core/lib/cmdline.c
+++ b/grub-core/lib/cmdline.c
@@ -20,6 +20,12 @@
 #include <grub/lib/cmdline.h>
 #include <grub/misc.h>
 
+static int
+is_hex(char c)
+{
+  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
 static unsigned int check_arg (char *c, int *has_space)
 {
   int space = 0;
@@ -27,7 +33,13 @@ static unsigned int check_arg (char *c, int *has_space)
 
   while (*c)
     {
-      if (*c == '\\' || *c == '\'' || *c == '"')
+      if (*c == '\\' && *(c+1) == 'x' && is_hex(*(c+2)) && is_hex(*(c+3)))
+	{
+	  size += 4;
+	  c += 4;
+	  continue;
+	}
+      else if (*c == '\\' || *c == '\'' || *c == '"')
 	size++;
       else if (*c == ' ')
 	space = 1;
@@ -59,6 +71,17 @@ unsigned int grub_loader_cmdline_size (int argc, char *argv[])
   return size;
 }
 
+static grub_int32_t
+hex_to_int(char c)
+{
+  int i = c | 0x20;
+  if (i >= '0' && i < '9')
+    return i - '0';
+  if (i >= 'a' && i < 'f')
+    return i - ('a' - 10);
+  return -1;
+}
+
 int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
 				grub_size_t size)
 {
@@ -82,7 +105,24 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
 
       while (*c)
 	{
-	  if (*c == '\\' || *c == '\'' || *c == '"')
+	  if (*c < 0x21 || *c > 0x7e)
+	    {
+	      char int_to_hex[] = "0123456789abcdef";
+	      *buf++ = '\\';
+	      *buf++ = 'x';
+	      *buf++ = int_to_hex[(*c & 0xf0) >> 4];
+	      *buf++ = int_to_hex[*c & 0xf];
+	      c++;
+	      continue;
+	    }
+	  else if (c[0] == '\\' && c[1] == 'x' && is_hex(c[2]) && is_hex(c[3]))
+	    {
+	      int a = (hex_to_int(c[2]) << 4) | (hex_to_int(c[3]) & 0xf);
+	      *buf++ = a & 0xff;
+	      c += 4;
+	      continue;
+	    }
+	  else if (*c == '\\' || *c == '\'' || *c == '"')
 	    *buf++ = '\\';
 
 	  *buf++ = *c;
diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
index b5e6eb0..85a4bea 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -52,6 +52,23 @@ static struct grub_script_scope *scope = 0;
 /* Wildcard translator for GRUB script.  */
 struct grub_script_wildcard_translator *grub_wildcard_translator;
 
+static int
+is_hex(char c)
+{
+  return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
+}
+
+static grub_int32_t
+hex_to_int(char c)
+{
+  int i = c | 0x20;
+  if (i >= '0' && i < '9')
+    return i - '0';
+  if (i >= 'a' && i < 'f')
+    return i - ('a' - 10);
+  return -1;
+}
+
 static char*
 wildcard_escape (const char *s)
 {
@@ -68,7 +85,16 @@ wildcard_escape (const char *s)
   i = 0;
   while ((ch = *s++))
     {
-      if (ch == '*' || ch == '\\' || ch == '?')
+      if (ch < 0x21 || ch > 0x7e)
+	{
+	  char int_to_hex[] = "0123456789abcdef";
+	  p[i++] = '\\';
+	  p[i++] = 'x';
+	  p[i++] = int_to_hex[(ch & 0xf0) >> 4];
+	  p[i++] = int_to_hex[ch & 0xf];
+	  continue;
+	}
+      else if (ch == '*' || ch == '\\' || ch == '?')
 	p[i++] = '\\';
       p[i++] = ch;
     }
@@ -92,7 +118,14 @@ wildcard_unescape (const char *s)
   i = 0;
   while ((ch = *s++))
     {
-      if (ch == '\\')
+      if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2]))
+	{
+	  int a = (hex_to_int(s[1]) << 4) | (hex_to_int(s[2]) & 0xf);
+	  p[i++] = a & 0xff;
+	  s += 3;
+	  continue;
+	}
+      else if (ch == '\\')
 	p[i++] = *s++;
       else
 	p[i++] = ch;
@@ -385,10 +418,20 @@ parse_string (const char *str,
     switch (*ptr)
       {
       case '\\':
-	escaped = !escaped;
-	if (!escaped && put)
-	  *((*put)++) = '\\';
-	ptr++;
+	if (!escaped && put && ptr[1] == 'x' && is_hex(ptr[2]) &&
+						is_hex(ptr[3]))
+	  {
+	    int a = (hex_to_int(ptr[2]) << 4) | (hex_to_int(ptr[3]) & 0xf);
+	    *((*put)++) = a & 0xff;
+	    ptr += 4;
+	  }
+	else
+	  {
+	    escaped = !escaped;
+	    if (!escaped && put)
+	      *((*put)++) = '\\';
+	    ptr++;
+	  }
 	break;
       case '$':
 	if (escaped)
-- 
1.7.12.1