From c670a4a91e1949ffb39989be8e3cec3944567f84 Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Mon, 1 Oct 2012 13:24:37 -0400 Subject: [PATCH 108/225] Don't escape "\x[[:hex:]][[:hex:]]" in command line wildcard parsing. This patch makes wildcard parsing of the config file leave "\x[[:hex:]][[:hex:]]" escape sequences in place. This allows us to pass in \x20 and similar without it being tokenized, so that it appears intact to all levels of the parser, which we need for e.g. filesystem labels in command line arguments. Based on the following patches fedora has shipped: * 41d002615 - Pass "\x[[:hex:]][[:hex:]]" straight through unmolested. (49 minutes ago) * 3ebad1305 - Don't munge raw spaces when we're doing our cmdline escaping (#923374) (49 minutes ago) Resolves: rhbz#855849 Resolves: rhbz#923374 Signed-off-by: Peter Jones Signed-off-by: Hans de Goede --- grub-core/commands/wildcard.c | 16 +++++++++++++++- grub-core/lib/cmdline.c | 25 +++++++++++++++++++++++-- grub-core/script/execute.c | 43 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c index 9b4e72766..02c46f9fd 100644 --- a/grub-core/commands/wildcard.c +++ b/grub-core/commands/wildcard.c @@ -462,6 +462,12 @@ check_file (const char *dir, const char *basename) return ctx.found; } +static int +is_hex(char c) +{ + return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); +} + static void unescape (char *out, const char *in, const char *end) { @@ -470,7 +476,15 @@ 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])) + { + *optr++ = *iptr++; + *optr++ = *iptr++; + *optr++ = *iptr++; + *optr++ = *iptr++; + 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 d5e10ee87..970ea868c 100644 --- a/grub-core/lib/cmdline.c +++ b/grub-core/lib/cmdline.c @@ -20,6 +20,12 @@ #include #include +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; @@ -85,7 +97,16 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf, while (*c) { - if (*c == '\\' || *c == '\'' || *c == '"') + if (*c == '\\' && *(c+1) == 'x' && + is_hex(*(c+2)) && is_hex(*(c+3))) + { + *buf++ = *c++; + *buf++ = *c++; + *buf++ = *c++; + *buf++ = *c++; + continue; + } + else if (*c == '\\' || *c == '\'' || *c == '"') *buf++ = '\\'; *buf++ = *c; diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index ab78ca87f..cf6cd6601 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -55,6 +55,12 @@ 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 char* wildcard_escape (const char *s) { @@ -71,7 +77,15 @@ wildcard_escape (const char *s) i = 0; while ((ch = *s++)) { - if (ch == '*' || ch == '\\' || ch == '?') + if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2])) + { + p[i++] = ch; + p[i++] = *s++; + p[i++] = *s++; + p[i++] = *s++; + continue; + } + else if (ch == '*' || ch == '\\' || ch == '?') p[i++] = '\\'; p[i++] = ch; } @@ -95,7 +109,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])) + { + p[i++] = '\\'; + p[i++] = *s++; + p[i++] = *s++; + p[i++] = *s++; + } + else if (ch == '\\') p[i++] = *s++; else p[i++] = ch; @@ -397,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))) + { + *(put++) = *ptr++; + *(put++) = *ptr++; + *(put++) = *ptr++; + *(put++) = *ptr++; + } + else + { + escaped = !escaped; + if (!escaped && put) + *(put++) = '\\'; + ptr++; + } break; case '$': if (escaped) -- 2.14.3