Michal Schmidt 14c310
From d2ebd2444f5ecf11e091e8108232ef6b3322f32f Mon Sep 17 00:00:00 2001
Michal Schmidt 14c310
From: Lennart Poettering <lennart@poettering.net>
Michal Schmidt 14c310
Date: Mon, 12 Mar 2012 22:22:16 +0100
Michal Schmidt 14c310
Subject: [PATCH] conf: enforce UTF8 validty everywhere
Michal Schmidt 14c310
Michal Schmidt 14c310
we need to make sure that configuration data we expose via the bus ends
Michal Schmidt 14c310
up in using getting an assert(). Even though configuration data is only
Michal Schmidt 14c310
parsed from trusted sources we should be more careful with what we read.
Michal Schmidt 14c310
(cherry picked from commit 7f110ff9b8828b477e87de7b28c708cf69a3d008)
Michal Schmidt 14c310
Michal Schmidt 14c310
Conflicts:
Michal Schmidt 14c310
Michal Schmidt 14c310
	Makefile.am
Michal Schmidt 14c310
	TODO
Michal Schmidt 14c310
---
Michal Schmidt 14c310
 Makefile.am         |    6 +-
Michal Schmidt 14c310
 src/conf-parser.c   |   66 ++++++++++++----
Michal Schmidt 14c310
 src/load-fragment.c |  102 ++++++++++++++-----------
Michal Schmidt 14c310
 src/service.c       |   13 +++-
Michal Schmidt 14c310
 src/utf8.c          |  214 +++++++++++++++++++++++++++++++++++++++++++++++++++
Michal Schmidt 14c310
 src/utf8.h          |   33 ++++++++
Michal Schmidt 14c310
 src/util.c          |   17 +++--
Michal Schmidt 14c310
 7 files changed, 382 insertions(+), 69 deletions(-)
Michal Schmidt 14c310
 create mode 100644 src/utf8.c
Michal Schmidt 14c310
 create mode 100644 src/utf8.h
Michal Schmidt 14c310
Michal Schmidt 14c310
diff --git a/Makefile.am b/Makefile.am
Michal Schmidt 14c310
index 295944d..2f5dcdb 100644
Michal Schmidt 14c310
--- a/Makefile.am
Michal Schmidt 14c310
+++ b/Makefile.am
Michal Schmidt 14c310
@@ -632,7 +632,8 @@ libsystemd_basic_la_SOURCES = \
Michal Schmidt 14c310
 	src/socket-util.c \
Michal Schmidt 14c310
 	src/log.c \
Michal Schmidt 14c310
 	src/ratelimit.c \
Michal Schmidt 14c310
-	src/exit-status.c
Michal Schmidt 14c310
+	src/exit-status.c \
Michal Schmidt 14c310
+	src/utf8.c
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 libsystemd_basic_la_CFLAGS = \
Michal Schmidt 14c310
 	$(AM_CFLAGS) \
Michal Schmidt 14c310
@@ -757,7 +758,8 @@ EXTRA_DIST += \
Michal Schmidt 14c310
         src/logind-user.h \
Michal Schmidt 14c310
         src/logind-acl.h \
Michal Schmidt 14c310
         src/dbus-loop.h \
Michal Schmidt 14c310
-        src/spawn-agent.h
Michal Schmidt 14c310
+        src/spawn-agent.h \
Michal Schmidt 14c310
+        src/utf8.h
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 MANPAGES = \
Michal Schmidt 14c310
 	man/systemd.1 \
Michal Schmidt 14c310
diff --git a/src/conf-parser.c b/src/conf-parser.c
Michal Schmidt 14c310
index af34378..9edf637 100644
Michal Schmidt 14c310
--- a/src/conf-parser.c
Michal Schmidt 14c310
+++ b/src/conf-parser.c
Michal Schmidt 14c310
@@ -30,6 +30,7 @@
Michal Schmidt 14c310
 #include "macro.h"
Michal Schmidt 14c310
 #include "strv.h"
Michal Schmidt 14c310
 #include "log.h"
Michal Schmidt 14c310
+#include "utf8.h"
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 int config_item_table_lookup(
Michal Schmidt 14c310
                 void *table,
Michal Schmidt 14c310
@@ -554,14 +555,23 @@ int config_parse_string(
Michal Schmidt 14c310
         assert(rvalue);
Michal Schmidt 14c310
         assert(data);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (*rvalue) {
Michal Schmidt 14c310
-                if (!(n = strdup(rvalue)))
Michal Schmidt 14c310
-                        return -ENOMEM;
Michal Schmidt 14c310
-        } else
Michal Schmidt 14c310
-                n = NULL;
Michal Schmidt 14c310
+        n = cunescape(rvalue);
Michal Schmidt 14c310
+        if (!n)
Michal Schmidt 14c310
+                return -ENOMEM;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        if (!utf8_is_valid(n)) {
Michal Schmidt 14c310
+                log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
Michal Schmidt 14c310
+                free(n);
Michal Schmidt 14c310
+                return 0;
Michal Schmidt 14c310
+        }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         free(*s);
Michal Schmidt 14c310
-        *s = n;
Michal Schmidt 14c310
+        if (*n)
Michal Schmidt 14c310
+                *s = n;
Michal Schmidt 14c310
+        else {
Michal Schmidt 14c310
+                free(n);
Michal Schmidt 14c310
+                *s = NULL;
Michal Schmidt 14c310
+        }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         return 0;
Michal Schmidt 14c310
 }
Michal Schmidt 14c310
@@ -584,12 +594,18 @@ int config_parse_path(
Michal Schmidt 14c310
         assert(rvalue);
Michal Schmidt 14c310
         assert(data);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
+        if (!utf8_is_valid(rvalue)) {
Michal Schmidt 14c310
+                log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
Michal Schmidt 14c310
+                return 0;
Michal Schmidt 14c310
+        }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
         if (!path_is_absolute(rvalue)) {
Michal Schmidt 14c310
                 log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
Michal Schmidt 14c310
                 return 0;
Michal Schmidt 14c310
         }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(n = strdup(rvalue)))
Michal Schmidt 14c310
+        n = strdup(rvalue);
Michal Schmidt 14c310
+        if (!n)
Michal Schmidt 14c310
                 return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         path_kill_slashes(n);
Michal Schmidt 14c310
@@ -616,6 +632,7 @@ int config_parse_strv(
Michal Schmidt 14c310
         unsigned k;
Michal Schmidt 14c310
         size_t l;
Michal Schmidt 14c310
         char *state;
Michal Schmidt 14c310
+        int r;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         assert(filename);
Michal Schmidt 14c310
         assert(lvalue);
Michal Schmidt 14c310
@@ -626,7 +643,8 @@ int config_parse_strv(
Michal Schmidt 14c310
         FOREACH_WORD_QUOTED(w, l, rvalue, state)
Michal Schmidt 14c310
                 k++;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(n = new(char*, k+1)))
Michal Schmidt 14c310
+        n = new(char*, k+1);
Michal Schmidt 14c310
+        if (!n)
Michal Schmidt 14c310
                 return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         if (*sv)
Michal Schmidt 14c310
@@ -635,9 +653,21 @@ int config_parse_strv(
Michal Schmidt 14c310
         else
Michal Schmidt 14c310
                 k = 0;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        FOREACH_WORD_QUOTED(w, l, rvalue, state)
Michal Schmidt 14c310
-                if (!(n[k++] = cunescape_length(w, l)))
Michal Schmidt 14c310
+        FOREACH_WORD_QUOTED(w, l, rvalue, state) {
Michal Schmidt 14c310
+                n[k] = cunescape_length(w, l);
Michal Schmidt 14c310
+                if (!n[k]) {
Michal Schmidt 14c310
+                        r = -ENOMEM;
Michal Schmidt 14c310
                         goto fail;
Michal Schmidt 14c310
+                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                if (!utf8_is_valid(n[k])) {
Michal Schmidt 14c310
+                        log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
Michal Schmidt 14c310
+                        free(n[k]);
Michal Schmidt 14c310
+                        continue;
Michal Schmidt 14c310
+                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                k++;
Michal Schmidt 14c310
+        }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         n[k] = NULL;
Michal Schmidt 14c310
         free(*sv);
Michal Schmidt 14c310
@@ -650,7 +680,7 @@ fail:
Michal Schmidt 14c310
                 free(n[k-1]);
Michal Schmidt 14c310
         free(n);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        return -ENOMEM;
Michal Schmidt 14c310
+        return r;
Michal Schmidt 14c310
 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 int config_parse_path_strv(
Michal Schmidt 14c310
@@ -680,7 +710,8 @@ int config_parse_path_strv(
Michal Schmidt 14c310
         FOREACH_WORD_QUOTED(w, l, rvalue, state)
Michal Schmidt 14c310
                 k++;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(n = new(char*, k+1)))
Michal Schmidt 14c310
+        n = new(char*, k+1);
Michal Schmidt 14c310
+        if (!n)
Michal Schmidt 14c310
                 return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         k = 0;
Michal Schmidt 14c310
@@ -689,11 +720,18 @@ int config_parse_path_strv(
Michal Schmidt 14c310
                         n[k] = (*sv)[k];
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
Michal Schmidt 14c310
-                if (!(n[k] = cunescape_length(w, l))) {
Michal Schmidt 14c310
+                n[k] = strndup(w, l);
Michal Schmidt 14c310
+                if (!n[k]) {
Michal Schmidt 14c310
                         r = -ENOMEM;
Michal Schmidt 14c310
                         goto fail;
Michal Schmidt 14c310
                 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
+                if (!utf8_is_valid(n[k])) {
Michal Schmidt 14c310
+                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
Michal Schmidt 14c310
+                        free(n[k]);
Michal Schmidt 14c310
+                        continue;
Michal Schmidt 14c310
+                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
                 if (!path_is_absolute(n[k])) {
Michal Schmidt 14c310
                         log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue);
Michal Schmidt 14c310
                         free(n[k]);
Michal Schmidt 14c310
@@ -701,7 +739,6 @@ int config_parse_path_strv(
Michal Schmidt 14c310
                 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 path_kill_slashes(n[k]);
Michal Schmidt 14c310
-
Michal Schmidt 14c310
                 k++;
Michal Schmidt 14c310
         }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
@@ -712,7 +749,6 @@ int config_parse_path_strv(
Michal Schmidt 14c310
         return 0;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 fail:
Michal Schmidt 14c310
-        free(n[k]);
Michal Schmidt 14c310
         for (; k > 0; k--)
Michal Schmidt 14c310
                 free(n[k-1]);
Michal Schmidt 14c310
         free(n);
Michal Schmidt 14c310
diff --git a/src/load-fragment.c b/src/load-fragment.c
Michal Schmidt 14c310
index ba28398..1d4a8c1 100644
Michal Schmidt 14c310
--- a/src/load-fragment.c
Michal Schmidt 14c310
+++ b/src/load-fragment.c
Michal Schmidt 14c310
@@ -43,6 +43,7 @@
Michal Schmidt 14c310
 #include "missing.h"
Michal Schmidt 14c310
 #include "unit-name.h"
Michal Schmidt 14c310
 #include "bus-errors.h"
Michal Schmidt 14c310
+#include "utf8.h"
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 #ifndef HAVE_SYSV_COMPAT
Michal Schmidt 14c310
 int config_parse_warn_compat(
Michal Schmidt 14c310
@@ -90,7 +91,6 @@ int config_parse_unit_deps(
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 k = unit_name_printf(u, t);
Michal Schmidt 14c310
                 free(t);
Michal Schmidt 14c310
-
Michal Schmidt 14c310
                 if (!k)
Michal Schmidt 14c310
                         return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
@@ -128,22 +128,18 @@ int config_parse_unit_names(
Michal Schmidt 14c310
                 char *t, *k;
Michal Schmidt 14c310
                 int r;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-                if (!(t = strndup(w, l)))
Michal Schmidt 14c310
+                t = strndup(w, l);
Michal Schmidt 14c310
+                if (!t)
Michal Schmidt 14c310
                         return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 k = unit_name_printf(u, t);
Michal Schmidt 14c310
                 free(t);
Michal Schmidt 14c310
-
Michal Schmidt 14c310
                 if (!k)
Michal Schmidt 14c310
                         return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 r = unit_merge_by_name(u, k);
Michal Schmidt 14c310
-
Michal Schmidt 14c310
-                if (r < 0) {
Michal Schmidt 14c310
+                if (r < 0)
Michal Schmidt 14c310
                         log_error("Failed to add name %s, ignoring: %s", k, strerror(-r));
Michal Schmidt 14c310
-                        free(k);
Michal Schmidt 14c310
-                        return 0;
Michal Schmidt 14c310
-                }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 free(k);
Michal Schmidt 14c310
         }
Michal Schmidt 14c310
@@ -162,27 +158,22 @@ int config_parse_unit_string_printf(
Michal Schmidt 14c310
                 void *userdata) {
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         Unit *u = userdata;
Michal Schmidt 14c310
-        char **s = data;
Michal Schmidt 14c310
         char *k;
Michal Schmidt 14c310
+        int r;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         assert(filename);
Michal Schmidt 14c310
         assert(lvalue);
Michal Schmidt 14c310
         assert(rvalue);
Michal Schmidt 14c310
-        assert(s);
Michal Schmidt 14c310
         assert(u);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(k = unit_full_printf(u, rvalue)))
Michal Schmidt 14c310
+        k = unit_full_printf(u, rvalue);
Michal Schmidt 14c310
+        if (!k)
Michal Schmidt 14c310
                 return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        free(*s);
Michal Schmidt 14c310
-        if (*k)
Michal Schmidt 14c310
-                *s = k;
Michal Schmidt 14c310
-        else {
Michal Schmidt 14c310
-                free(k);
Michal Schmidt 14c310
-                *s = NULL;
Michal Schmidt 14c310
-        }
Michal Schmidt 14c310
+        r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
Michal Schmidt 14c310
+        free (k);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        return 0;
Michal Schmidt 14c310
+        return r;
Michal Schmidt 14c310
 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 int config_parse_unit_strv_printf(
Michal Schmidt 14c310
@@ -225,30 +216,22 @@ int config_parse_unit_path_printf(
Michal Schmidt 14c310
                 void *userdata) {
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         Unit *u = userdata;
Michal Schmidt 14c310
-        char **s = data;
Michal Schmidt 14c310
         char *k;
Michal Schmidt 14c310
+        int r;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         assert(filename);
Michal Schmidt 14c310
         assert(lvalue);
Michal Schmidt 14c310
         assert(rvalue);
Michal Schmidt 14c310
-        assert(s);
Michal Schmidt 14c310
         assert(u);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(k = unit_full_printf(u, rvalue)))
Michal Schmidt 14c310
+        k = unit_full_printf(u, rvalue);
Michal Schmidt 14c310
+        if (!k)
Michal Schmidt 14c310
                 return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!path_is_absolute(k)) {
Michal Schmidt 14c310
-                log_error("[%s:%u] Not an absolute path: %s", filename, line, k);
Michal Schmidt 14c310
-                free(k);
Michal Schmidt 14c310
-                return -EINVAL;
Michal Schmidt 14c310
-        }
Michal Schmidt 14c310
-
Michal Schmidt 14c310
-        path_kill_slashes(k);
Michal Schmidt 14c310
-
Michal Schmidt 14c310
-        free(*s);
Michal Schmidt 14c310
-        *s = k;
Michal Schmidt 14c310
+        r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
Michal Schmidt 14c310
+        free(k);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        return 0;
Michal Schmidt 14c310
+        return r;
Michal Schmidt 14c310
 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 int config_parse_socket_listen(
Michal Schmidt 14c310
@@ -271,7 +254,8 @@ int config_parse_socket_listen(
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         s = (Socket*) data;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(p = new0(SocketPort, 1)))
Michal Schmidt 14c310
+        p = new0(SocketPort, 1);
Michal Schmidt 14c310
+        if (!p)
Michal Schmidt 14c310
                 return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         if (streq(lvalue, "ListenFIFO")) {
Michal Schmidt 14c310
@@ -478,6 +462,7 @@ int config_parse_exec(
Michal Schmidt 14c310
         ExecCommand **e = data, *nce;
Michal Schmidt 14c310
         char *path, **n;
Michal Schmidt 14c310
         unsigned k;
Michal Schmidt 14c310
+        int r;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         assert(filename);
Michal Schmidt 14c310
         assert(lvalue);
Michal Schmidt 14c310
@@ -528,7 +513,8 @@ int config_parse_exec(
Michal Schmidt 14c310
                         k++;
Michal Schmidt 14c310
                 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-                if (!(n = new(char*, k + !honour_argv0)))
Michal Schmidt 14c310
+                n = new(char*, k + !honour_argv0);
Michal Schmidt 14c310
+                if (!n)
Michal Schmidt 14c310
                         return -ENOMEM;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 k = 0;
Michal Schmidt 14c310
@@ -538,11 +524,33 @@ int config_parse_exec(
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                         if (honour_argv0 && w == rvalue) {
Michal Schmidt 14c310
                                 assert(!path);
Michal Schmidt 14c310
-                                if (!(path = cunescape_length(w, l)))
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                                path = strndup(w, l);
Michal Schmidt 14c310
+                                if (!path) {
Michal Schmidt 14c310
+                                        r = -ENOMEM;
Michal Schmidt 14c310
                                         goto fail;
Michal Schmidt 14c310
+                                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                                if (!utf8_is_valid(path)) {
Michal Schmidt 14c310
+                                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
Michal Schmidt 14c310
+                                        r = 0;
Michal Schmidt 14c310
+                                        goto fail;
Michal Schmidt 14c310
+                                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
                         } else {
Michal Schmidt 14c310
-                                if (!(n[k++] = cunescape_length(w, l)))
Michal Schmidt 14c310
+                                char *c;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                                c = n[k++] = cunescape_length(w, l);
Michal Schmidt 14c310
+                                if (!c) {
Michal Schmidt 14c310
+                                        r = -ENOMEM;
Michal Schmidt 14c310
                                         goto fail;
Michal Schmidt 14c310
+                                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                                if (!utf8_is_valid(c)) {
Michal Schmidt 14c310
+                                        log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
Michal Schmidt 14c310
+                                        r = 0;
Michal Schmidt 14c310
+                                        goto fail;
Michal Schmidt 14c310
+                                }
Michal Schmidt 14c310
                         }
Michal Schmidt 14c310
                 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
@@ -550,19 +558,25 @@ int config_parse_exec(
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 if (!n[0]) {
Michal Schmidt 14c310
                         log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
Michal Schmidt 14c310
-                        strv_free(n);
Michal Schmidt 14c310
-                        free(path);
Michal Schmidt 14c310
-                        return 0;
Michal Schmidt 14c310
+                        r = 0;
Michal Schmidt 14c310
+                        goto fail;
Michal Schmidt 14c310
                 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-                if (!path)
Michal Schmidt 14c310
-                        if (!(path = strdup(n[0])))
Michal Schmidt 14c310
+                if (!path) {
Michal Schmidt 14c310
+                        path = strdup(n[0]);
Michal Schmidt 14c310
+                        if (!path) {
Michal Schmidt 14c310
+                                r = -ENOMEM;
Michal Schmidt 14c310
                                 goto fail;
Michal Schmidt 14c310
+                        }
Michal Schmidt 14c310
+                }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 assert(path_is_absolute(path));
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-                if (!(nce = new0(ExecCommand, 1)))
Michal Schmidt 14c310
+                nce = new0(ExecCommand, 1);
Michal Schmidt 14c310
+                if (!nce) {
Michal Schmidt 14c310
+                        r = -ENOMEM;
Michal Schmidt 14c310
                         goto fail;
Michal Schmidt 14c310
+                }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 nce->argv = n;
Michal Schmidt 14c310
                 nce->path = path;
Michal Schmidt 14c310
@@ -583,7 +597,7 @@ fail:
Michal Schmidt 14c310
         free(path);
Michal Schmidt 14c310
         free(nce);
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        return -ENOMEM;
Michal Schmidt 14c310
+        return r;
Michal Schmidt 14c310
 }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
Michal Schmidt 14c310
diff --git a/src/service.c b/src/service.c
Michal Schmidt 14c310
index af83b6e..9005b02 100644
Michal Schmidt 14c310
--- a/src/service.c
Michal Schmidt 14c310
+++ b/src/service.c
Michal Schmidt 14c310
@@ -37,6 +37,7 @@
Michal Schmidt 14c310
 #include "exit-status.h"
Michal Schmidt 14c310
 #include "def.h"
Michal Schmidt 14c310
 #include "util.h"
Michal Schmidt 14c310
+#include "utf8.h"
Michal Schmidt 14c310
 
Michal Schmidt 14c310
 #ifdef HAVE_SYSV_COMPAT
Michal Schmidt 14c310
 
Michal Schmidt 14c310
@@ -3033,11 +3034,19 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags) {
Michal Schmidt 14c310
         }
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         /* Interpret STATUS= */
Michal Schmidt 14c310
-        if ((e = strv_find_prefix(tags, "STATUS="))) {
Michal Schmidt 14c310
+        e = strv_find_prefix(tags, "STATUS=");
Michal Schmidt 14c310
+        if (e) {
Michal Schmidt 14c310
                 char *t;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
                 if (e[7]) {
Michal Schmidt 14c310
-                        if (!(t = strdup(e+7))) {
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if (!utf8_is_valid(e+7)) {
Michal Schmidt 14c310
+                                log_warning("Status message in notification is not UTF-8 clean.");
Michal Schmidt 14c310
+                                return;
Michal Schmidt 14c310
+                        }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        t = strdup(e+7);
Michal Schmidt 14c310
+                        if (!t) {
Michal Schmidt 14c310
                                 log_error("Failed to allocate string.");
Michal Schmidt 14c310
                                 return;
Michal Schmidt 14c310
                         }
Michal Schmidt 14c310
diff --git a/src/utf8.c b/src/utf8.c
Michal Schmidt 14c310
new file mode 100644
Michal Schmidt 14c310
index 0000000..11619dc
Michal Schmidt 14c310
--- /dev/null
Michal Schmidt 14c310
+++ b/src/utf8.c
Michal Schmidt 14c310
@@ -0,0 +1,214 @@
Michal Schmidt 14c310
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+/***
Michal Schmidt 14c310
+  This file is part of systemd.
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  Copyright 2012 Lennart Poettering
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  systemd is free software; you can redistribute it and/or modify it
Michal Schmidt 14c310
+  under the terms of the GNU General Public License as published by
Michal Schmidt 14c310
+  the Free Software Foundation; either version 2 of the License, or
Michal Schmidt 14c310
+  (at your option) any later version.
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  systemd is distributed in the hope that it will be useful, but
Michal Schmidt 14c310
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Michal Schmidt 14c310
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Michal Schmidt 14c310
+  General Public License for more details.
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  You should have received a copy of the GNU General Public License
Michal Schmidt 14c310
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Michal Schmidt 14c310
+***/
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+/* This file is based on the GLIB utf8 validation functions. The
Michal Schmidt 14c310
+ * original license text follows. */
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+/* gutf8.c - Operations on UTF-8 strings.
Michal Schmidt 14c310
+ *
Michal Schmidt 14c310
+ * Copyright (C) 1999 Tom Tromey
Michal Schmidt 14c310
+ * Copyright (C) 2000 Red Hat, Inc.
Michal Schmidt 14c310
+ *
Michal Schmidt 14c310
+ * This library is free software; you can redistribute it and/or
Michal Schmidt 14c310
+ * modify it under the terms of the GNU Lesser General Public
Michal Schmidt 14c310
+ * License as published by the Free Software Foundation; either
Michal Schmidt 14c310
+ * version 2 of the License, or (at your option) any later version.
Michal Schmidt 14c310
+ *
Michal Schmidt 14c310
+ * This library is distributed in the hope that it will be useful,
Michal Schmidt 14c310
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
Michal Schmidt 14c310
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the GNU
Michal Schmidt 14c310
+ * Lesser General Public License for more details.
Michal Schmidt 14c310
+ *
Michal Schmidt 14c310
+ * You should have received a copy of the GNU Lesser General Public
Michal Schmidt 14c310
+ * License along with this library; if not, write to the
Michal Schmidt 14c310
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Michal Schmidt 14c310
+ * Boston, MA 02111-1307, USA.
Michal Schmidt 14c310
+ */
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+#include <errno.h>
Michal Schmidt 14c310
+#include <stdlib.h>
Michal Schmidt 14c310
+#include <inttypes.h>
Michal Schmidt 14c310
+#include <string.h>
Michal Schmidt 14c310
+#include <stdbool.h>
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+#include "utf8.h"
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+#define FILTER_CHAR '_'
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+static inline bool is_unicode_valid(uint32_t ch) {
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        if (ch >= 0x110000) /* End of unicode space */
Michal Schmidt 14c310
+                return false;
Michal Schmidt 14c310
+        if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */
Michal Schmidt 14c310
+                return false;
Michal Schmidt 14c310
+        if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */
Michal Schmidt 14c310
+                return false;
Michal Schmidt 14c310
+        if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */
Michal Schmidt 14c310
+                return false;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        return true;
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+static inline bool is_continuation_char(uint8_t ch) {
Michal Schmidt 14c310
+        if ((ch & 0xc0) != 0x80) /* 10xxxxxx */
Michal Schmidt 14c310
+                return false;
Michal Schmidt 14c310
+        return true;
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) {
Michal Schmidt 14c310
+        *u_ch <<= 6;
Michal Schmidt 14c310
+        *u_ch |= ch & 0x3f;
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+static char* utf8_validate(const char *str, char *output) {
Michal Schmidt 14c310
+        uint32_t val = 0;
Michal Schmidt 14c310
+        uint32_t min = 0;
Michal Schmidt 14c310
+        const uint8_t *p, *last;
Michal Schmidt 14c310
+        int size;
Michal Schmidt 14c310
+        uint8_t *o;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        assert(str);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        o = (uint8_t*) output;
Michal Schmidt 14c310
+        for (p = (const uint8_t*) str; *p; p++) {
Michal Schmidt 14c310
+                if (*p < 128) {
Michal Schmidt 14c310
+                        if (o)
Michal Schmidt 14c310
+                                *o = *p;
Michal Schmidt 14c310
+                } else {
Michal Schmidt 14c310
+                        last = p;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */
Michal Schmidt 14c310
+                                size = 2;
Michal Schmidt 14c310
+                                min = 128;
Michal Schmidt 14c310
+                                val = (uint32_t) (*p & 0x1e);
Michal Schmidt 14c310
+                                goto ONE_REMAINING;
Michal Schmidt 14c310
+                        } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/
Michal Schmidt 14c310
+                                size = 3;
Michal Schmidt 14c310
+                                min = (1 << 11);
Michal Schmidt 14c310
+                                val = (uint32_t) (*p & 0x0f);
Michal Schmidt 14c310
+                                goto TWO_REMAINING;
Michal Schmidt 14c310
+                        } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */
Michal Schmidt 14c310
+                                size = 4;
Michal Schmidt 14c310
+                                min = (1 << 16);
Michal Schmidt 14c310
+                                val = (uint32_t) (*p & 0x07);
Michal Schmidt 14c310
+                        } else
Michal Schmidt 14c310
+                                goto error;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        p++;
Michal Schmidt 14c310
+                        if (!is_continuation_char(*p))
Michal Schmidt 14c310
+                                goto error;
Michal Schmidt 14c310
+                        merge_continuation_char(&val, *p);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                TWO_REMAINING:
Michal Schmidt 14c310
+                        p++;
Michal Schmidt 14c310
+                        if (!is_continuation_char(*p))
Michal Schmidt 14c310
+                                goto error;
Michal Schmidt 14c310
+                        merge_continuation_char(&val, *p);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                ONE_REMAINING:
Michal Schmidt 14c310
+                        p++;
Michal Schmidt 14c310
+                        if (!is_continuation_char(*p))
Michal Schmidt 14c310
+                                goto error;
Michal Schmidt 14c310
+                        merge_continuation_char(&val, *p);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if (val < min)
Michal Schmidt 14c310
+                                goto error;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if (!is_unicode_valid(val))
Michal Schmidt 14c310
+                                goto error;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if (o) {
Michal Schmidt 14c310
+                                memcpy(o, last, (size_t) size);
Michal Schmidt 14c310
+                                o += size;
Michal Schmidt 14c310
+                        }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        continue;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                error:
Michal Schmidt 14c310
+                        if (o) {
Michal Schmidt 14c310
+                                *o = FILTER_CHAR;
Michal Schmidt 14c310
+                                p = last; /* We retry at the next character */
Michal Schmidt 14c310
+                        } else
Michal Schmidt 14c310
+                                goto failure;
Michal Schmidt 14c310
+                }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                if (o)
Michal Schmidt 14c310
+                        o++;
Michal Schmidt 14c310
+        }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        if (o) {
Michal Schmidt 14c310
+                *o = '\0';
Michal Schmidt 14c310
+                return output;
Michal Schmidt 14c310
+        }
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        return (char*) str;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+failure:
Michal Schmidt 14c310
+        return NULL;
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+char* utf8_is_valid (const char *str) {
Michal Schmidt 14c310
+        return utf8_validate(str, NULL);
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+char* utf8_filter (const char *str) {
Michal Schmidt 14c310
+        char *new_str;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        assert(str);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        new_str = malloc(strlen(str) + 1);
Michal Schmidt 14c310
+        if (!new_str)
Michal Schmidt 14c310
+                return NULL;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        return utf8_validate(str, new_str);
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+char *ascii_is_valid(const char *str) {
Michal Schmidt 14c310
+        const char *p;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        assert(str);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        for (p = str; *p; p++)
Michal Schmidt 14c310
+                if ((unsigned char) *p >= 128)
Michal Schmidt 14c310
+                        return NULL;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        return (char*) str;
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+char *ascii_filter(const char *str) {
Michal Schmidt 14c310
+        char *r, *s, *d;
Michal Schmidt 14c310
+        size_t l;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        assert(str);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        l = strlen(str);
Michal Schmidt 14c310
+        r = malloc(l + 1);
Michal Schmidt 14c310
+        if (!r)
Michal Schmidt 14c310
+                return NULL;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        for (s = r, d = r; *s; s++)
Michal Schmidt 14c310
+                if ((unsigned char) *s < 128)
Michal Schmidt 14c310
+                        *(d++) = *s;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        *d = 0;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+        return r;
Michal Schmidt 14c310
+}
Michal Schmidt 14c310
diff --git a/src/utf8.h b/src/utf8.h
Michal Schmidt 14c310
new file mode 100644
Michal Schmidt 14c310
index 0000000..9a72bec
Michal Schmidt 14c310
--- /dev/null
Michal Schmidt 14c310
+++ b/src/utf8.h
Michal Schmidt 14c310
@@ -0,0 +1,33 @@
Michal Schmidt 14c310
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+#ifndef fooutf8hfoo
Michal Schmidt 14c310
+#define fooutf8hfoo
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+/***
Michal Schmidt 14c310
+  This file is part of systemd.
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  Copyright 2012 Lennart Poettering
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  systemd is free software; you can redistribute it and/or modify it
Michal Schmidt 14c310
+  under the terms of the GNU General Public License as published by
Michal Schmidt 14c310
+  the Free Software Foundation; either version 2 of the License, or
Michal Schmidt 14c310
+  (at your option) any later version.
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  systemd is distributed in the hope that it will be useful, but
Michal Schmidt 14c310
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Michal Schmidt 14c310
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Michal Schmidt 14c310
+  General Public License for more details.
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+  You should have received a copy of the GNU General Public License
Michal Schmidt 14c310
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Michal Schmidt 14c310
+***/
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+#include "macro.h"
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+char *utf8_is_valid(const char *s) _pure_;
Michal Schmidt 14c310
+char *ascii_is_valid(const char *s) _pure_;
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+char *utf8_filter(const char *s);
Michal Schmidt 14c310
+char *ascii_filter(const char *s);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+#endif
Michal Schmidt 14c310
diff --git a/src/util.c b/src/util.c
Michal Schmidt 14c310
index 6a2c61f..0c9537e 100644
Michal Schmidt 14c310
--- a/src/util.c
Michal Schmidt 14c310
+++ b/src/util.c
Michal Schmidt 14c310
@@ -1773,7 +1773,8 @@ char *cunescape_length(const char *s, size_t length) {
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         /* Undoes C style string escaping */
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-        if (!(r = new(char, length+1)))
Michal Schmidt 14c310
+        r = new(char, length+1);
Michal Schmidt 14c310
+        if (!r)
Michal Schmidt 14c310
                 return r;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
         for (f = s, t = r; f < s + length; f++) {
Michal Schmidt 14c310
@@ -1827,8 +1828,10 @@ char *cunescape_length(const char *s, size_t length) {
Michal Schmidt 14c310
                         /* hexadecimal encoding */
Michal Schmidt 14c310
                         int a, b;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-                        if ((a = unhexchar(f[1])) < 0 ||
Michal Schmidt 14c310
-                            (b = unhexchar(f[2])) < 0) {
Michal Schmidt 14c310
+                        a = unhexchar(f[1]);
Michal Schmidt 14c310
+                        b = unhexchar(f[2]);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if (a < 0 || b < 0) {
Michal Schmidt 14c310
                                 /* Invalid escape code, let's take it literal then */
Michal Schmidt 14c310
                                 *(t++) = '\\';
Michal Schmidt 14c310
                                 *(t++) = 'x';
Michal Schmidt 14c310
@@ -1851,9 +1854,11 @@ char *cunescape_length(const char *s, size_t length) {
Michal Schmidt 14c310
                         /* octal encoding */
Michal Schmidt 14c310
                         int a, b, c;
Michal Schmidt 14c310
 
Michal Schmidt 14c310
-                        if ((a = unoctchar(f[0])) < 0 ||
Michal Schmidt 14c310
-                            (b = unoctchar(f[1])) < 0 ||
Michal Schmidt 14c310
-                            (c = unoctchar(f[2])) < 0) {
Michal Schmidt 14c310
+                        a = unoctchar(f[0]);
Michal Schmidt 14c310
+                        b = unoctchar(f[1]);
Michal Schmidt 14c310
+                        c = unoctchar(f[2]);
Michal Schmidt 14c310
+
Michal Schmidt 14c310
+                        if (a < 0 || b < 0 || c < 0) {
Michal Schmidt 14c310
                                 /* Invalid escape code, let's take it literal then */
Michal Schmidt 14c310
                                 *(t++) = '\\';
Michal Schmidt 14c310
                                 *(t++) = f[0];