1ff636
From 030a063371f4f4fd0d4366ebd3cebfa9930773da Mon Sep 17 00:00:00 2001
1ff636
From: Martin Pitt <martin.pitt@ubuntu.com>
1ff636
Date: Wed, 22 Apr 2015 23:09:43 +0100
1ff636
Subject: [PATCH] util: Fix assertion in split() on missing '
1ff636
1ff636
When parsing a unit with a trailing slash after an escaped line break, like
1ff636
1ff636
  ExecStart=/bin/echo 'foo \
1ff636
    bar'
1ff636
1ff636
the split() function (through config_parse()) asserted and crashed pid 1:
1ff636
1ff636
  Assertion 'current[*l + 1] == quotechars[0]' failed at ../src/shared/util.c:583, function split(). Aborting.
1ff636
1ff636
Fix this by returning an error in this case ("trailing garbage").
1ff636
1ff636
Add corresponding test case. Also fix the missing "unit" argument of
1ff636
config_parse_exec() in the comment.
1ff636
1ff636
https://launchpad.net/bugs/1447243
1ff636
(cherry picked from commit 470dca63cd2b1579f45f72b6b9777494abeff105)
1ff636
1ff636
Cherry-picked from: 8f93633
1ff636
Resolves: #1222517
1ff636
---
1ff636
 src/shared/util.c         |  3 +--
1ff636
 src/test/test-unit-file.c | 15 +++++++++++++++
1ff636
 2 files changed, 16 insertions(+), 2 deletions(-)
1ff636
1ff636
diff --git a/src/shared/util.c b/src/shared/util.c
c62b8e
index 1e1bf944f2..649344d88f 100644
1ff636
--- a/src/shared/util.c
1ff636
+++ b/src/shared/util.c
1ff636
@@ -571,13 +571,12 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
1ff636
                 char quotechars[2] = {*current, '\0'};
1ff636
 
1ff636
                 *l = strcspn_escaped(current + 1, quotechars);
1ff636
-                if (current[*l + 1] == '\0' ||
1ff636
+                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
1ff636
                     (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
1ff636
                         /* right quote missing or garbage at the end */
1ff636
                         *state = current;
1ff636
                         return NULL;
1ff636
                 }
1ff636
-                assert(current[*l + 1] == quotechars[0]);
1ff636
                 *state = current++ + *l + 2;
1ff636
         } else if (quoted) {
1ff636
                 *l = strcspn_escaped(current, separator);
1ff636
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
c62b8e
index e517f571d6..9f3e3a227e 100644
1ff636
--- a/src/test/test-unit-file.c
1ff636
+++ b/src/test/test-unit-file.c
1ff636
@@ -92,6 +92,7 @@ static void check_execcommand(ExecCommand *c,
1ff636
 
1ff636
 static void test_config_parse_exec(void) {
1ff636
         /* int config_parse_exec(
1ff636
+                 const char *unit,
1ff636
                  const char *filename,
1ff636
                  unsigned line,
1ff636
                  const char *section,
1ff636
@@ -303,6 +304,20 @@ static void test_config_parse_exec(void) {
1ff636
         assert_se(r == 0);
1ff636
         assert_se(c1->command_next == NULL);
1ff636
 
1ff636
+        log_info("/* missing ending ' */");
1ff636
+        r = config_parse_exec(NULL, "fake", 4, "section", 1,
1ff636
+                              "LValue", 0, "/path 'foo",
1ff636
+                              &c, NULL);
1ff636
+        assert_se(r == 0);
1ff636
+        assert_se(c1->command_next == NULL);
1ff636
+
1ff636
+        log_info("/* missing ending ' with trailing backslash */");
1ff636
+        r = config_parse_exec(NULL, "fake", 4, "section", 1,
1ff636
+                              "LValue", 0, "/path 'foo\\",
1ff636
+                              &c, NULL);
1ff636
+        assert_se(r == 0);
1ff636
+        assert_se(c1->command_next == NULL);
1ff636
+
1ff636
         exec_command_free_list(c);
1ff636
 }
1ff636