Pablo Greco 48fc63
From 650d5c39753d095f8ae6cff418306cf1a6b8fd25 Mon Sep 17 00:00:00 2001
Pablo Greco 48fc63
From: Jan Synacek <jsynacek@redhat.com>
Pablo Greco 48fc63
Date: Fri, 2 Nov 2018 08:40:40 +0100
Pablo Greco 48fc63
Subject: [PATCH] =?UTF-8?q?core:=20when=20deserializing=20state=20always?=
Pablo Greco 48fc63
 =?UTF-8?q?=20use=20read=5Fline(=E2=80=A6,=20LONG=5FLINE=5FMAX,=20?=
Pablo Greco 48fc63
 =?UTF-8?q?=E2=80=A6)?=
Pablo Greco 48fc63
MIME-Version: 1.0
Pablo Greco 48fc63
Content-Type: text/plain; charset=UTF-8
Pablo Greco 48fc63
Content-Transfer-Encoding: 8bit
Pablo Greco 48fc63
Pablo Greco 48fc63
This should be much better than fgets(), as we can read substantially
Pablo Greco 48fc63
longer lines and overly long lines result in proper errors.
Pablo Greco 48fc63
Pablo Greco 48fc63
Fixes a vulnerability discovered by Jann Horn at Google.
Pablo Greco 48fc63
Pablo Greco 48fc63
(cherry picked from commit 8948b3415d762245ebf5e19d80b97d4d8cc208c1)
Pablo Greco 48fc63
Pablo Greco 48fc63
Resolves: CVE-2018-15686
Pablo Greco 48fc63
Pablo Greco 48fc63
[jsynacek] There were more commits in the pull request of which the cherry
Pablo Greco 48fc63
picked commit was a part of, see
Pablo Greco 48fc63
https://github.com/systemd/systemd/pull/10519/commits.
Pablo Greco 48fc63
I decided not to backport any of the remaining ones, because they were
Pablo Greco 48fc63
mostly irrelevant to the actual fix.
Pablo Greco 48fc63
---
Pablo Greco 48fc63
 src/core/job.c     | 19 +++++++++++--------
Pablo Greco 48fc63
 src/core/manager.c | 38 ++++++++++++++++----------------------
Pablo Greco 48fc63
 src/core/unit.c    | 17 ++++++++---------
Pablo Greco 48fc63
 3 files changed, 35 insertions(+), 39 deletions(-)
Pablo Greco 48fc63
Pablo Greco 48fc63
diff --git a/src/core/job.c b/src/core/job.c
Pablo Greco 48fc63
index 275503169b..998b231ed9 100644
Pablo Greco 48fc63
--- a/src/core/job.c
Pablo Greco 48fc63
+++ b/src/core/job.c
Pablo Greco 48fc63
@@ -38,6 +38,7 @@
Pablo Greco 48fc63
 #include "async.h"
Pablo Greco 48fc63
 #include "virt.h"
Pablo Greco 48fc63
 #include "dbus.h"
Pablo Greco 48fc63
+#include "fileio.h"
Pablo Greco 48fc63
 
Pablo Greco 48fc63
 Job* job_new_raw(Unit *unit) {
Pablo Greco 48fc63
         Job *j;
Pablo Greco 48fc63
@@ -1035,23 +1036,25 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
Pablo Greco 48fc63
 }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
 int job_deserialize(Job *j, FILE *f, FDSet *fds) {
Pablo Greco 48fc63
+        int r = 0;
Pablo Greco 48fc63
+
Pablo Greco 48fc63
         assert(j);
Pablo Greco 48fc63
 
Pablo Greco 48fc63
         for (;;) {
Pablo Greco 48fc63
-                char line[LINE_MAX], *l, *v;
Pablo Greco 48fc63
+                _cleanup_free_ char *line = NULL;
Pablo Greco 48fc63
+                char *l, *v;
Pablo Greco 48fc63
                 size_t k;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                if (!fgets(line, sizeof(line), f)) {
Pablo Greco 48fc63
-                        if (feof(f))
Pablo Greco 48fc63
-                                return 0;
Pablo Greco 48fc63
-                        return -errno;
Pablo Greco 48fc63
-                }
Pablo Greco 48fc63
+                r = read_line(f, LONG_LINE_MAX, &line);
Pablo Greco 48fc63
+                if (r < 0)
Pablo Greco 48fc63
+                        return log_error_errno(r, "Failed to read serialization line: %m");
Pablo Greco 48fc63
+                if (r == 0)
Pablo Greco 48fc63
+                        return 0;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                char_array_0(line);
Pablo Greco 48fc63
                 l = strstrip(line);
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                 /* End marker */
Pablo Greco 48fc63
-                if (l[0] == 0)
Pablo Greco 48fc63
+                if (isempty(l))
Pablo Greco 48fc63
                         return 0;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                 k = strcspn(l, "=");
Pablo Greco 48fc63
diff --git a/src/core/manager.c b/src/core/manager.c
Pablo Greco 48fc63
index 0466e4bb8a..73d6c81fdb 100644
Pablo Greco 48fc63
--- a/src/core/manager.c
Pablo Greco 48fc63
+++ b/src/core/manager.c
Pablo Greco 48fc63
@@ -37,6 +37,7 @@
Pablo Greco 48fc63
 #include <sys/stat.h>
Pablo Greco 48fc63
 #include <dirent.h>
Pablo Greco 48fc63
 #include <sys/timerfd.h>
Pablo Greco 48fc63
+#include <fileio.h>
Pablo Greco 48fc63
 
Pablo Greco 48fc63
 #ifdef HAVE_AUDIT
Pablo Greco 48fc63
 #include <libaudit.h>
Pablo Greco 48fc63
@@ -2559,21 +2560,19 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
Pablo Greco 48fc63
         m->n_reloading ++;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
         for (;;) {
Pablo Greco 48fc63
-                char line[LINE_MAX], *l;
Pablo Greco 48fc63
+                _cleanup_free_ char *line = NULL;
Pablo Greco 48fc63
+                char *l;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                if (!fgets(line, sizeof(line), f)) {
Pablo Greco 48fc63
-                        if (feof(f))
Pablo Greco 48fc63
-                                r = 0;
Pablo Greco 48fc63
-                        else
Pablo Greco 48fc63
-                                r = -errno;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                        goto finish;
Pablo Greco 48fc63
-                }
Pablo Greco 48fc63
+                r = read_line(f, LONG_LINE_MAX, &line);
Pablo Greco 48fc63
+                if (r < 0)
Pablo Greco 48fc63
+                        return log_error_errno(r, "Failed to read serialization line: %m");
Pablo Greco 48fc63
+                if (r == 0)
Pablo Greco 48fc63
+                        break;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                char_array_0(line);
Pablo Greco 48fc63
                 l = strstrip(line);
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                if (l[0] == 0)
Pablo Greco 48fc63
+                 if (isempty(l)) /* end marker */
Pablo Greco 48fc63
                         break;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                 if (startswith(l, "current-job-id=")) {
Pablo Greco 48fc63
@@ -2708,22 +2707,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
Pablo Greco 48fc63
         }
Pablo Greco 48fc63
 
Pablo Greco 48fc63
         for (;;) {
Pablo Greco 48fc63
+                _cleanup_free_ char *line = NULL;
Pablo Greco 48fc63
                 Unit *u;
Pablo Greco 48fc63
-                char name[UNIT_NAME_MAX+2];
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                 /* Start marker */
Pablo Greco 48fc63
-                if (!fgets(name, sizeof(name), f)) {
Pablo Greco 48fc63
-                        if (feof(f))
Pablo Greco 48fc63
-                                r = 0;
Pablo Greco 48fc63
-                        else
Pablo Greco 48fc63
-                                r = -errno;
Pablo Greco 48fc63
-
Pablo Greco 48fc63
-                        goto finish;
Pablo Greco 48fc63
-                }
Pablo Greco 48fc63
-
Pablo Greco 48fc63
-                char_array_0(name);
Pablo Greco 48fc63
+                r = read_line(f, LONG_LINE_MAX, &line);
Pablo Greco 48fc63
+                if (r < 0)
Pablo Greco 48fc63
+                        return log_error_errno(r, "Failed to read serialization line: %m");
Pablo Greco 48fc63
+                if (r == 0)
Pablo Greco 48fc63
+                        break;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                r = manager_load_unit(m, strstrip(name), NULL, NULL, &u);
Pablo Greco 48fc63
+                r = manager_load_unit(m, strstrip(line), NULL, NULL, &u);
Pablo Greco 48fc63
                 if (r < 0)
Pablo Greco 48fc63
                         goto finish;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
diff --git a/src/core/unit.c b/src/core/unit.c
Pablo Greco 48fc63
index e8532a057d..37fac8db3a 100644
Pablo Greco 48fc63
--- a/src/core/unit.c
Pablo Greco 48fc63
+++ b/src/core/unit.c
Pablo Greco 48fc63
@@ -2644,20 +2644,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
Pablo Greco 48fc63
                 rt = (ExecRuntime**) ((uint8_t*) u + offset);
Pablo Greco 48fc63
 
Pablo Greco 48fc63
         for (;;) {
Pablo Greco 48fc63
-                char line[LINE_MAX], *l, *v;
Pablo Greco 48fc63
+                 _cleanup_free_ char *line = NULL;
Pablo Greco 48fc63
+                char *l, *v;
Pablo Greco 48fc63
                 size_t k;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                if (!fgets(line, sizeof(line), f)) {
Pablo Greco 48fc63
-                        if (feof(f))
Pablo Greco 48fc63
-                                return 0;
Pablo Greco 48fc63
-                        return -errno;
Pablo Greco 48fc63
-                }
Pablo Greco 48fc63
+                r = read_line(f, LONG_LINE_MAX, &line);
Pablo Greco 48fc63
+                if (r < 0)
Pablo Greco 48fc63
+                        return log_error_errno(r, "Failed to read serialization line: %m");
Pablo Greco 48fc63
+                if (r == 0) /* eof */
Pablo Greco 48fc63
+                        return 0;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
-                char_array_0(line);
Pablo Greco 48fc63
                 l = strstrip(line);
Pablo Greco 48fc63
-
Pablo Greco 48fc63
                 /* End marker */
Pablo Greco 48fc63
-                if (l[0] == 0)
Pablo Greco 48fc63
+                if (isempty(l))
Pablo Greco 48fc63
                         return 0;
Pablo Greco 48fc63
 
Pablo Greco 48fc63
                 k = strcspn(l, "=");