Blame SOURCES/0004-grubby-properly-handle-mixed-and-and-nested-quotes.patch

24fce8
From d58e447819e96d84560b16d7632bb7bdf88cc412 Mon Sep 17 00:00:00 2001
24fce8
From: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
24fce8
Date: Tue, 16 Jun 2015 10:43:21 -0700
24fce8
Subject: [PATCH 04/55] grubby: properly handle mixed ' and " and nested quotes
24fce8
24fce8
The SLES12 grub2.cfg file on ppc64le by default contains a line like:
24fce8
24fce8
  submenu "Bootable snapshot #$snapshot_num" {
24fce8
    menuentry "If OK, run 'snapper rollback $snapshot_num' reboot." { true; }
24fce8
  }
24fce8
24fce8
On any grubby (tested with 8.40) invocation that updates the config
24fce8
file, the combination of nested quotes and mixed quotes leads to a
24fce8
generated file content like:
24fce8
24fce8
  submenu "Bootable snapshot #$snapshot_num" {
24fce8
    menuentry 'If OK, run snapper rollback $snapshot_num' rollback $snapshot_num' and reboot." { true; }
24fce8
  }
24fce8
24fce8
which includes both a change from " to ', but also improperly quoted
24fce8
strings and trailing characters relative to the string. This actually
24fce8
leads to a failure to boot from the disk by default when using grubby
24fce8
(e.g., Autotest) on SLES12 ppc64le. Whether SLES12 should be adding an
24fce8
entry like this by default or not is probably open to debate, but grubby
24fce8
should be able to hand this input file.
24fce8
24fce8
To fix the issue, three changes were necessary:
24fce8
24fce8
1) grub2ExtractTitle needs to check that if the second element starts
24fce8
with a quote, that the matching element found ends with the same
24fce8
quote-type (' vs. ")
24fce8
24fce8
2) lineWrite needs to output the right kind of quote based upon if the
24fce8
string to be outputted itself contains quotes. This is not currently
24fce8
possible in the code, because quotes are stripped out normally by
24fce8
readConfig, but with the change in 3), that only happens now for the
24fce8
quotes that actually delineate a string.
24fce8
24fce8
3) readConfig needs to check that when it is extracting titles and
24fce8
determining extras, it uses matching quotes.
24fce8
24fce8
With these changes, a simple grubby --set-default=SLES12 (for example),
24fce8
now produces:
24fce8
24fce8
   submenu "Bootable snapshot #$snapshot_num" {
24fce8
     menuentry "If OK, run 'snapper rollback $snapshot_num' and reboot." { true; }
24fce8
   }
24fce8
24fce8
as expected.
24fce8
24fce8
Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
24fce8
---
24fce8
 grubby.c | 42 +++++++++++++++++++++++++++++++++---------
24fce8
 1 file changed, 33 insertions(+), 9 deletions(-)
24fce8
24fce8
diff --git a/grubby.c b/grubby.c
24fce8
index 53fe9250e27..440c6277935 100644
24fce8
--- a/grubby.c
24fce8
+++ b/grubby.c
24fce8
@@ -451,6 +451,8 @@ char *grub2ExtractTitle(struct singleLine * line) {
24fce8
      * whose last character is also quote (assuming it's the closing one) */
24fce8
     int resultMaxSize;
24fce8
     char * result;
24fce8
+    /* need to ensure that ' does not match " as we search */
24fce8
+    char quote_char = *current;
24fce8
     
24fce8
     resultMaxSize = sizeOfSingleLine(line);
24fce8
     result = malloc(resultMaxSize);
24fce8
@@ -464,7 +466,7 @@ char *grub2ExtractTitle(struct singleLine * line) {
24fce8
 	current_indent_len = strlen(current_indent);
24fce8
 
24fce8
 	strncat(result, current_indent, current_indent_len);
24fce8
-	if (!isquote(current[current_len-1])) {
24fce8
+	if (current[current_len-1] != quote_char) {
24fce8
 	    strncat(result, current, current_len);
24fce8
 	} else {
24fce8
 	    strncat(result, current, current_len - 1);
24fce8
@@ -928,10 +930,23 @@ static int lineWrite(FILE * out, struct singleLine * line,
24fce8
 	/* Need to handle this, because we strip the quotes from
24fce8
 	 * menuentry when read it. */
24fce8
 	if (line->type == LT_MENUENTRY && i == 1) {
24fce8
-	    if(!isquote(*line->elements[i].item))
24fce8
-		fprintf(out, "\'%s\'", line->elements[i].item);
24fce8
-	    else
24fce8
+	    if(!isquote(*line->elements[i].item)) {
24fce8
+		int substring = 0;
24fce8
+		/* If the line contains nested quotes, we did not strip
24fce8
+		 * the "interna" quotes and we must use the right quotes
24fce8
+		 * again when writing the updated file. */
24fce8
+		for (int j = i; j < line->numElements; j++) {
24fce8
+		    if (strchr(line->elements[i].item, '\'') != NULL) {
24fce8
+		       substring = 1;
24fce8
+		       fprintf(out, "\"%s\"", line->elements[i].item);
24fce8
+		       break;
24fce8
+		    }
24fce8
+		}
24fce8
+		if (!substring)
24fce8
+		    fprintf(out, "\'%s\'", line->elements[i].item);
24fce8
+	    } else {
24fce8
 		fprintf(out, "%s", line->elements[i].item);
24fce8
+	    }
24fce8
 	    fprintf(out, "%s", line->elements[i].indent);
24fce8
 
24fce8
 	    continue;
24fce8
@@ -1267,6 +1282,8 @@ static struct grubConfig * readConfig(const char * inName,
24fce8
 	    len = 0;
24fce8
 	    char *extras;
24fce8
 	    char *title;
24fce8
+	    /* initially unseen value */
24fce8
+	    char quote_char = '\0';
24fce8
 
24fce8
 	    for (int i = 1; i < line->numElements; i++) {
24fce8
 		len += strlen(line->elements[i].item);
24fce8
@@ -1283,13 +1300,16 @@ static struct grubConfig * readConfig(const char * inName,
24fce8
 	    for (int i = 0; i < line->numElements; i++) {
24fce8
 		if (!strcmp(line->elements[i].item, "menuentry"))
24fce8
 		    continue;
24fce8
-		if (isquote(*line->elements[i].item))
24fce8
+		if (isquote(*line->elements[i].item) && quote_char == '\0') {
24fce8
+		    /* ensure we properly pair off quotes */
24fce8
+		    quote_char = *line->elements[i].item;
24fce8
 		    title = line->elements[i].item + 1;
24fce8
-		else
24fce8
+		} else {
24fce8
 		    title = line->elements[i].item;
24fce8
+		}
24fce8
 
24fce8
 		len = strlen(title);
24fce8
-	        if (isquote(title[len-1])) {
24fce8
+	        if (title[len-1] == quote_char) {
24fce8
 		    strncat(buf, title,len-1);
24fce8
 		    break;
24fce8
 		} else {
24fce8
@@ -1300,6 +1320,7 @@ static struct grubConfig * readConfig(const char * inName,
24fce8
 
24fce8
 	    /* get extras */
24fce8
 	    int count = 0;
24fce8
+	    quote_char = '\0';
24fce8
 	    for (int i = 0; i < line->numElements; i++) {
24fce8
 		if (count >= 2) {
24fce8
 		    strcat(extras, line->elements[i].item);
24fce8
@@ -1310,12 +1331,15 @@ static struct grubConfig * readConfig(const char * inName,
24fce8
 		    continue;
24fce8
 
24fce8
 		/* count ' or ", there should be two in menuentry line. */
24fce8
-		if (isquote(*line->elements[i].item))
24fce8
+		if (isquote(*line->elements[i].item) && quote_char == '\0') {
24fce8
+		    /* ensure we properly pair off quotes */
24fce8
+	            quote_char = *line->elements[i].item;
24fce8
 		    count++;
24fce8
+		}
24fce8
 
24fce8
 		len = strlen(line->elements[i].item);
24fce8
 
24fce8
-		if (isquote(line->elements[i].item[len -1]))
24fce8
+		if (line->elements[i].item[len -1] == quote_char)
24fce8
 		    count++;
24fce8
 
24fce8
 		/* ok, we get the final ' or ", others are extras. */
24fce8
-- 
24fce8
2.17.1
24fce8