Bug 90794

Summary: [v220 regression] "Failed to unescape command line"
Product: systemd Reporter: Peter Wu <peter>
Component: generalAssignee: systemd-bugs
Status: RESOLVED FIXED QA Contact: systemd-bugs
Severity: normal    
Priority: medium CC: filbranden, martin.pitt, mbiebl
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: test case patch

Description Peter Wu 2015-05-31 17:59:06 UTC
Since upgrading from v218-1 to systemd v220-3 (on Arch Linux), one of my services fail to get parsed with the following error:

[/usr/lib/systemd/system/ssh-blocker.service:13] Failed to unescape command line, ignoring: -/bin/sh -c "for ip in $(grep ^AllowUsers /etc/ssh/sshd_config | grep -Po '\w+@\K[\d.]+');  do /usr/sbin/ipset -exist add ssh-whitelist $ip timeout 0; done"

Line 13 is ([WRAP] added for clarity):
ExecStartPost=-/bin/sh -c "for ip in [WRAP]
$(grep ^AllowUsers /etc/ssh/sshd_config | [WRAP]
grep -Po '\w+@\K[\d.]+'); \
do /usr/sbin/ipset -exist add ssh-whitelist $ip timeout 0; done"

(service at https://github.com/Lekensteyn/ssh-blocker/blob/master/systemd/ssh-blocker.service.in#L13)

Another report is from the Debian people (https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=787256):
[/lib/systemd/system/sudo.service:7] Failed to unescape command line, ignoring: /usr/bin/find /var/lib/sudo -exec /usr/bin/touch -d @0 '{}' \073
(service file at http://anonscm.debian.org/cgit/collab-maint/sudo.git/tree/debian/sudo.service#n7)

It is probably related to this change (nowhere mentioned in NEWS...):

    commit 4034a06ddb82ec9868cd52496fef2f5faa25575f (tags/v220~644)
    Author: Lennart Poettering <lennart@poettering.net>
    Date:   Mon Mar 23 18:55:36 2015 +0700

        util: rework word parsing and c unescaping code
Comment 1 Daniel Mack 2015-06-01 14:03:13 UTC
It seems this broke with commit 527b7a42 ("util: rework cunescape(), improve error handling"). As load-fragment.c does not pass the UNESCAPE_RELAX flag to cunescape(), the code now errors out in the attempt of unescaping the quoted perl regexp '\w+@\K[\d.]+', which it didn't before. As this is clearly a regression from an older version of systemd, I guess the best we can do is to restore the old behavior and gracefully handles unescaping errors by copying the characters verbatim that cannot be unescaped.

Lennart, any reason why you omitted this flag for that specific use case?

My proposed fix would be:

diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index c95c110..df5fe6f 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -610,7 +610,7 @@ int config_parse_exec(
                         else
                                 skip = strneq(word, "\\;", MAX(l, 1U));
 
-                        r = cunescape_length(word + skip, l - skip, 0, &c);
+                        r = cunescape_length(word + skip, l - skip, UNESCAPE_RELAX, &c);
                         if (r < 0) {
                                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to unescape command line, ignoring: %s", rvalue);
                                 r = 0;
Comment 2 Martin Pitt 2015-06-01 15:21:26 UTC
Created attachment 116206 [details] [review]
test case patch

This should really get committed with a corresponding test case. This patch adds the gist of the two downstream bug reports.
Comment 3 Daniel Mack 2015-06-01 16:12:00 UTC
This is now fixed upstream with 22874a348f. I also added the test case from Martin as separate commit on top.
Comment 4 Michael Biebl 2015-06-02 21:18:08 UTC
Even with this patch applied, I still get failures when trying to start sudo.service.

Without the patch, I got:

Mai 30 15:06:24 pluto systemd[1]: [/lib/systemd/system/sudo.service:7] Failed to unescape command line, ignoring: /usr/bin/find /var/lib/sudo -exec /usr/bin/touch -d @0 '{}' \073
Mai 30 15:06:24 pluto systemd[1]: sudo.service: Service lacks both ExecStart= and ExecStop= setting. Refusing.

Now I get:
# systemctl status sudo.service
● sudo.service - Provide limited super user privileges to specific users
   Loaded: loaded (/lib/systemd/system/sudo.service; enabled; vendor preset: enabled)
   Active: failed (Result: exit-code) since Di 2015-06-02 22:42:28 CEST; 30min ago
  Process: 743 ExecStart=/usr/bin/find /var/lib/sudo -exec /usr/bin/touch -d @0 {} \073 (code=exited, status=1/FAILURE)
 Main PID: 743 (code=exited, status=1/FAILURE)

Jun 02 22:42:28 pluto systemd[1]: Starting Provide limited super user privileges to specific users...
Jun 02 22:42:28 pluto systemd[1]: sudo.service: Main process exited, code=exited, status=1/FAILURE
Jun 02 22:42:28 pluto systemd[1]: Failed to start Provide limited super user privileges to specific users.
Jun 02 22:42:28 pluto systemd[1]: sudo.service: Unit entered failed state.
Jun 02 22:42:28 pluto systemd[1]: sudo.service: Failed with result 'exit-code'.
Jun 02 22:42:28 pluto find[743]: /usr/bin/find: Fehlendes Argument für "-exec".

So it still behaves differently then in v215.
This is the comment from sudo.service

# \073 is ';' which needs to be part of the find parameters
ExecStart=/usr/bin/find /var/lib/sudo -exec /usr/bin/touch -d @0 '{}' \073


Looks like systemd v215 did turn \073 into \; ?
Comment 5 Daniel Mack 2015-06-03 11:51:25 UTC
Could you try this patch?

  https://github.com/zonque/systemd/commit/19c9c4173.patch

I opened a pull request here:

  https://github.com/systemd/systemd/pull/51


Thanks for reporting this!
Comment 6 Martin Pitt 2015-06-04 10:49:55 UTC
Works fine now, thanks!

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.