aboutsummaryrefslogtreecommitdiff
path: root/sys/boot/common/interp_parse.c
diff options
context:
space:
mode:
authorAllan Jude <allanjude@FreeBSD.org>2016-07-30 17:53:37 +0000
committerAllan Jude <allanjude@FreeBSD.org>2016-07-30 17:53:37 +0000
commitaafbb33897d6215934ffdcc0946c3242ff811ac5 (patch)
tree54f1b458d92cd30dff08b2814c318c33d4d7f842 /sys/boot/common/interp_parse.c
parent6bf8d16009cff0a5e945bb9055f1297ebfff7e85 (diff)
downloadsrc-aafbb33897d6215934ffdcc0946c3242ff811ac5.tar.gz
src-aafbb33897d6215934ffdcc0946c3242ff811ac5.zip
Improve boot loader quote parsing
parse() is the boot loader's interp_parse.c is too naive about quotes both single and double quotes were allowed to be mixed, and single quotes did not follow the usual semantics (re variable expansion). The old code did not check for terminating quotes This update implements: * distinguishing single and double quote * variable expansion will not be done inside single quote protected area * will preserve inner quote for values like "value 'some list'" * ending quote check. this diff does not implement ending quote order check, it shouldn't be too hard, needs some improvements on parser state machine. PR: 204602 Submitted by: Toomas Soome <tsoome@me.com> Relnotes: yes Differential Revision: https://reviews.freebsd.org/D6000
Notes
Notes: svn path=/head/; revision=303556
Diffstat (limited to 'sys/boot/common/interp_parse.c')
-rw-r--r--sys/boot/common/interp_parse.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/sys/boot/common/interp_parse.c b/sys/boot/common/interp_parse.c
index 32d4f48240e8..8d8a2e290983 100644
--- a/sys/boot/common/interp_parse.c
+++ b/sys/boot/common/interp_parse.c
@@ -72,7 +72,13 @@ isdelim(int ch)
static int
isquote(int ch)
{
- return (ch == '\'' || ch == '"');
+ return (ch == '\'');
+}
+
+static int
+isdquote(int ch)
+{
+ return (ch == '"');
}
int
@@ -81,11 +87,11 @@ parse(int *argc, char ***argv, char *str)
int ac;
char *val, *p, *q, *copy = NULL;
size_t i = 0;
- char token, tmp, quote, *buf;
+ char token, tmp, quote, dquote, *buf;
enum { STR, VAR, WHITE } state;
ac = *argc = 0;
- quote = 0;
+ dquote = quote = 0;
if (!str || (p = copy = backslash(str)) == NULL)
return 1;
@@ -105,9 +111,19 @@ parse(int *argc, char ***argv, char *str)
buf[i++] = *p++;
} else if (isquote(*p)) {
quote = quote ? 0 : *p;
- ++p;
- }
- else if (isspace(*p) && !quote) {
+ if (dquote) { /* keep quote */
+ PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
+ buf[i++] = *p++;
+ } else
+ ++p;
+ } else if (isdquote(*p)) {
+ dquote = dquote ? 0 : *p;
+ if (quote) { /* keep dquote */
+ PARSE_FAIL(i == (PARSE_BUFSIZE - 1));
+ buf[i++] = *p++;
+ } else
+ ++p;
+ } else if (isspace(*p) && !quote && !dquote) {
state = WHITE;
if (i) {
buf[i] = '\0';
@@ -115,7 +131,7 @@ parse(int *argc, char ***argv, char *str)
i = 0;
}
++p;
- } else if (*p == '$') {
+ } else if (*p == '$' && !quote) {
token = isdelim(*(p + 1));
if (token)
p += 2;
@@ -157,6 +173,8 @@ parse(int *argc, char ***argv, char *str)
break;
}
}
+ /* missing terminating ' or " */
+ PARSE_FAIL(quote || dquote);
/* If at end of token, add it */
if (i && state == STR) {
buf[i] = '\0';