systemd: backport patches to fix 3 CVEs
cover systemd: backport patches to fix 3 CVEs
The following changes since commit 411184bfaa6269bf2926bb2a576c0922958cbbb3:
xserver-xorg: fix CVE-2018-14665 (2018-11-01 13:27:26 +0000)
are available in the git repository at:
git://git.pokylinux.org/poky-contrib ChenQi/systemd-CVEs
http://git.pokylinux.org/cgit.cgi/poky-contrib/log/?h=ChenQi/systemd-CVEs
Chen Qi (3):
systemd: fix CVE-2018-15686
systemd: fix CVE-2018-15687
systemd: fix CVE-2018-15688
...sive-let-s-rework-the-recursive-logic-to-.patch | 216 +++++++++++++++++++ ...eserializing-state-always-use-read_line-L.patch | 238 +++++++++++++++++++++ ...sure-we-have-enough-space-for-the-DHCP6-o.patch | 36 ++++ meta/recipes-core/systemd/systemd_239.bb | 3 + 4 files changed, 493 insertions(+) create mode 100644 meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch create mode 100644 meta/recipes-core/systemd/systemd/0001-core-when-deserializing-state-always-use-read_line-L.patch create mode 100644 meta/recipes-core/systemd/systemd/0001-dhcp6-make-sure-we-have-enough-space-for-the-DHCP6-o.patch
Signature · 1 line
1.9.1
PATCH 1/3 systemd: fix CVE-2018-15686
Backport patch to fix the following CVE.
CVE: CVE-2018-15686
--- ...eserializing-state-always-use-read_line-L.patch | 238 +++++++++++++++++++++ meta/recipes-core/systemd/systemd_239.bb | 1 + 2 files changed, 239 insertions(+) create mode 100644 meta/recipes-core/systemd/systemd/0001-core-when-deserializing-state-always-use-read_line-L.patch
meta/recipes-core/systemd/systemd/0001-core-when-deserializing-state-always-use-read_line-L.patch new file +238 -0
@@ -0,0 +1,238 @@ +From 47c45a237c1e51e987bb1607a1739338e5364724 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering <[email protected]> +Date: Wed, 17 Oct 2018 18:36:24 +0200 +Subject: [PATCH] =?UTF-8?q?core:=20when=20deserializing=20state=20always?= + =?UTF-8?q?=20use=20read=5Fline(=E2=80=A6,=20LONG=5FLINE=5FMAX,=20?= + =?UTF-8?q?=E2=80=A6)?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This should be much better than fgets(), as we can read substantially +longer lines and overly long lines result in proper errors. + +Fixes a vulnerability discovered by Jann Horn at Google. + +CVE-2018-15686 +LP: #1796402 +https://bugzilla.redhat.com/show_bug.cgi?id=1639071 + +Upstream-Status: Backport +[Modifed to fit the 239 version.] + +Signed-off-by: Chen Qi <[email protected]> +--- + src/core/job.c | 19 +++++++++++-------- + src/core/manager.c | 47 ++++++++++++++++++++--------------------------- + src/core/unit.c | 34 ++++++++++++++++++---------------- + src/core/unit.h | 2 +- + 4 files changed, 50 insertions(+), 52 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 734756b..8552ffb 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -10,6 +10,7 @@ + #include "dbus-job.h" + #include "dbus.h" + #include "escape.h" ++#include "fileio.h" + #include "job.h" + #include "log.h" + #include "macro.h" +@@ -1091,24 +1092,26 @@ int job_serialize(Job *j, FILE *f) { + } + + int job_deserialize(Job *j, FILE *f) { ++ int r; ++ + assert(j); + assert(f); + + for (;;) { +- char line[LINE_MAX], *l, *v; ++ _cleanup_free_ char *line = NULL; ++ char *l, *v; + size_t k; + +- if (!fgets(line, sizeof(line), f)) { +- if (feof(f)) +- return 0; +- return -errno; +- } ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) ++ return log_error_errno(r, "Failed to read serialization line: %m"); ++ if (r == 0) ++ return 0; + +- char_array_0(line); + l = strstrip(line); + + /* End marker */ +- if (l[0] == 0) ++ if (isempty(l)) + return 0; + + k = strcspn(l, "="); +diff --git a/src/core/manager.c b/src/core/manager.c +index 930df4e..879ae79 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -3130,22 +3130,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + m->n_reloading++; + + for (;;) { +- char line[LINE_MAX]; ++ _cleanup_free_ char *line = NULL; + const char *val, *l; + +- if (!fgets(line, sizeof(line), f)) { +- if (feof(f)) +- r = 0; +- else +- r = -errno; +- +- goto finish; +- } ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) ++ return log_error_errno(r, "Failed to read serialization line: %m"); ++ if (r == 0) ++ break; + +- char_array_0(line); + l = strstrip(line); +- +- if (l[0] == 0) ++ if (isempty(l)) /* end marker */ + break; + + if ((val = startswith(l, "current-job-id="))) { +@@ -3312,29 +3307,27 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + } + + for (;;) { +- Unit *u; +- char name[UNIT_NAME_MAX+2]; ++ _cleanup_free_ char *line = NULL; + const char* unit_name; ++ Unit *u; + + /* Start marker */ +- if (!fgets(name, sizeof(name), f)) { +- if (feof(f)) +- r = 0; +- else +- r = -errno; +- +- goto finish; +- } ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) ++ return log_error_errno(r, "Failed to read serialization line: %m"); ++ if (r == 0) ++ break; + +- char_array_0(name); +- unit_name = strstrip(name); ++ unit_name = strstrip(line); + + r = manager_load_unit(m, unit_name, NULL, NULL, &u); + if (r < 0) { + log_notice_errno(r, "Failed to load unit \"%s\", skipping deserialization: %m", unit_name); +- if (r == -ENOMEM) +- goto finish; +- unit_deserialize_skip(f); ++ ++ r = unit_deserialize_skip(f); ++ if (r < 0) ++ return r; ++ + continue; + } + +diff --git a/src/core/unit.c b/src/core/unit.c +index 113205b..a3556cc 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3368,21 +3368,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + assert(fds); + + for (;;) { +- char line[LINE_MAX], *l, *v; ++ _cleanup_free_ char *line = NULL; + CGroupIPAccountingMetric m; ++ char *l, *v; + size_t k; + +- if (!fgets(line, sizeof(line), f)) { +- if (feof(f)) +- return 0; +- return -errno; +- } ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) ++ return log_error_errno(r, "Failed to read serialization line: %m"); ++ if (r == 0) /* eof */ ++ break; + +- char_array_0(line); + l = strstrip(line); +- +- /* End marker */ +- if (isempty(l)) ++ if (isempty(l)) /* End marker */ + break; + + k = strcspn(l, "="); +@@ -3657,23 +3655,27 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + return 0; + } + +-void unit_deserialize_skip(FILE *f) { ++int unit_deserialize_skip(FILE *f) { ++ int r; + assert(f); + + /* Skip serialized data for this unit. We don't know what it is. */ + + for (;;) { +- char line[LINE_MAX], *l; ++ _cleanup_free_ char *line = NULL; ++ char *l; + +- if (!fgets(line, sizeof line, f)) +- return; ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) ++ return log_error_errno(r, "Failed to read serialization line: %m"); ++ if (r == 0) ++ return 0; + +- char_array_0(line); + l = strstrip(line); + + /* End marker */ + if (isempty(l)) +- return; ++ return 1; + } + } + +diff --git a/src/core/unit.h b/src/core/unit.h +index b3131eb..e1a60da 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -679,7 +679,7 @@ bool unit_can_serialize(Unit *u) _pure_; + + int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); + int unit_deserialize(Unit *u, FILE *f, FDSet *fds); +-void unit_deserialize_skip(FILE *f); ++int unit_deserialize_skip(FILE *f); + + int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); + int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value); +-- +2.7.4 +
meta/recipes-core/systemd/systemd_239.bb +1 -0
@@ -30,6 +30,7 @@ SRC_URI += "file://touchscreen.rules \ file://0001-sd-bus-make-BUS_DEFAULT_TIMEOUT-configurable.patch \ file://0022-build-sys-Detect-whether-struct-statx-is-defined-in-.patch \ file://0023-resolvconf-fixes-for-the-compatibility-interface.patch \ + file://0001-core-when-deserializing-state-always-use-read_line-L.patch \ " # patches made for musl are only applied on TCLIBC is musl
Signature · 1 line
1.9.1
PATCH 2/3 systemd: fix CVE-2018-15687
In reply to Chen QiBackport patch to fix the following CVE.
CVE: CVE-2018-15687
--- ...sive-let-s-rework-the-recursive-logic-to-.patch | 216 +++++++++++++++++++++ meta/recipes-core/systemd/systemd_239.bb | 1 + 2 files changed, 217 insertions(+) create mode 100644 meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch
meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch new file +216 -0
@@ -0,0 +1,216 @@ +From 7735278e9330c1b945862f31b3267827c9592b23 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering <[email protected]> +Date: Fri, 19 Oct 2018 11:26:59 +0200 +Subject: [PATCH] chown-recursive: let's rework the recursive logic to use + O_PATH + +That way we can pin a specific inode and analyze it and manipulate it +without it being swapped out beneath our hands. + +Fixes a vulnerability originally found by Jann Horn from Google. + +CVE-2018-15687 +LP: #1796692 +https://bugzilla.redhat.com/show_bug.cgi?id=1639076 + +Upstream-Status: Backport + +Signed-off-by: Chen Qi <[email protected]> +--- + src/core/chown-recursive.c | 146 ++++++++++++++++++++++----------------------- + 1 file changed, 70 insertions(+), 76 deletions(-) + +diff --git a/src/core/chown-recursive.c b/src/core/chown-recursive.c +index c479450..27c6448 100644 +--- a/src/core/chown-recursive.c ++++ b/src/core/chown-recursive.c +@@ -1,17 +1,19 @@ + /* SPDX-License-Identifier: LGPL-2.1+ */ + +-#include <sys/types.h> +-#include <sys/stat.h> + #include <fcntl.h> ++#include <sys/stat.h> ++#include <sys/types.h> + +-#include "user-util.h" +-#include "macro.h" +-#include "fd-util.h" +-#include "dirent-util.h" + #include "chown-recursive.h" ++#include "dirent-util.h" ++#include "fd-util.h" ++#include "macro.h" ++#include "stdio-util.h" ++#include "strv.h" ++#include "user-util.h" + +-static int chown_one(int fd, const char *name, const struct stat *st, uid_t uid, gid_t gid) { +- int r; ++static int chown_one(int fd, const struct stat *st, uid_t uid, gid_t gid) { ++ char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + + assert(fd >= 0); + assert(st); +@@ -20,90 +22,82 @@ static int chown_one(int fd, const char *name, const struct stat *st, uid_t uid, + (!gid_is_valid(gid) || st->st_gid == gid)) + return 0; + +- if (name) +- r = fchownat(fd, name, uid, gid, AT_SYMLINK_NOFOLLOW); +- else +- r = fchown(fd, uid, gid); +- if (r < 0) +- return -errno; ++ /* We change ownership through the /proc/self/fd/%i path, so that we have a stable reference that works with ++ * O_PATH. (Note: fchown() and fchmod() do not work with O_PATH, the kernel refuses that. */ ++ xsprintf(procfs_path, "/proc/self/fd/%i", fd); + +- /* The linux kernel alters the mode in some cases of chown(). Let's undo this. */ +- if (name) { +- if (!S_ISLNK(st->st_mode)) +- r = fchmodat(fd, name, st->st_mode, 0); +- else /* There's currently no AT_SYMLINK_NOFOLLOW for fchmodat() */ +- r = 0; +- } else +- r = fchmod(fd, st->st_mode); +- if (r < 0) ++ if (chown(procfs_path, uid, gid) < 0) + return -errno; + ++ /* The linux kernel alters the mode in some cases of chown(). Let's undo this. We do this only for non-symlinks ++ * however. That's because for symlinks the access mode is ignored anyway and because on some kernels/file ++ * systems trying to change the access mode will succeed but has no effect while on others it actively ++ * fails. */ ++ if (!S_ISLNK(st->st_mode)) ++ if (chmod(procfs_path, st->st_mode & 07777) < 0) ++ return -errno; ++ + return 1; + } + + static int chown_recursive_internal(int fd, const struct stat *st, uid_t uid, gid_t gid) { ++ _cleanup_closedir_ DIR *d = NULL; + bool changed = false; ++ struct dirent *de; + int r; + + assert(fd >= 0); + assert(st); + +- if (S_ISDIR(st->st_mode)) { +- _cleanup_closedir_ DIR *d = NULL; +- struct dirent *de; +- +- d = fdopendir(fd); +- if (!d) { +- r = -errno; +- goto finish; +- } +- fd = -1; +- +- FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) { +- struct stat fst; +- +- if (dot_or_dot_dot(de->d_name)) +- continue; +- +- if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) { +- r = -errno; +- goto finish; +- } +- +- if (S_ISDIR(fst.st_mode)) { +- int subdir_fd; +- +- subdir_fd = openat(dirfd(d), de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); +- if (subdir_fd < 0) { +- r = -errno; +- goto finish; +- } +- +- r = chown_recursive_internal(subdir_fd, &fst, uid, gid); +- if (r < 0) +- goto finish; +- if (r > 0) +- changed = true; +- } else { +- r = chown_one(dirfd(d), de->d_name, &fst, uid, gid); +- if (r < 0) +- goto finish; +- if (r > 0) +- changed = true; +- } ++ d = fdopendir(fd); ++ if (!d) { ++ safe_close(fd); ++ return -errno; ++ } ++ ++ FOREACH_DIRENT_ALL(de, d, return -errno) { ++ _cleanup_close_ int path_fd = -1; ++ struct stat fst; ++ ++ if (dot_or_dot_dot(de->d_name)) ++ continue; ++ ++ /* Let's pin the child inode we want to fix now with an O_PATH fd, so that it cannot be swapped out ++ * while we manipulate it. */ ++ path_fd = openat(dirfd(d), de->d_name, O_PATH|O_CLOEXEC|O_NOFOLLOW); ++ if (path_fd < 0) ++ return -errno; ++ ++ if (fstat(path_fd, &fst) < 0) ++ return -errno; ++ ++ if (S_ISDIR(fst.st_mode)) { ++ int subdir_fd; ++ ++ /* Convert it to a "real" (i.e. non-O_PATH) fd now */ ++ subdir_fd = fd_reopen(path_fd, O_RDONLY|O_CLOEXEC|O_NOATIME); ++ if (subdir_fd < 0) ++ return subdir_fd; ++ ++ r = chown_recursive_internal(subdir_fd, &fst, uid, gid); /* takes possession of subdir_fd even on failure */ ++ if (r < 0) ++ return r; ++ if (r > 0) ++ changed = true; ++ } else { ++ r = chown_one(path_fd, &fst, uid, gid); ++ if (r < 0) ++ return r; ++ if (r > 0) ++ changed = true; + } ++ } + +- r = chown_one(dirfd(d), NULL, st, uid, gid); +- } else +- r = chown_one(fd, NULL, st, uid, gid); ++ r = chown_one(dirfd(d), st, uid, gid); + if (r < 0) +- goto finish; ++ return r; + +- r = r > 0 || changed; +- +-finish: +- safe_close(fd); +- return r; ++ return r > 0 || changed; + } + + int path_chown_recursive(const char *path, uid_t uid, gid_t gid) { +@@ -111,7 +105,7 @@ int path_chown_recursive(const char *path, uid_t uid, gid_t gid) { + struct stat st; + int r; + +- fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); ++ fd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (fd < 0) + return -errno; + +-- +2.7.4 +
meta/recipes-core/systemd/systemd_239.bb +1 -0
@@ -31,6 +31,7 @@ SRC_URI += "file://touchscreen.rules \ file://0022-build-sys-Detect-whether-struct-statx-is-defined-in-.patch \ file://0023-resolvconf-fixes-for-the-compatibility-interface.patch \ file://0001-core-when-deserializing-state-always-use-read_line-L.patch \ + file://0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch \ " # patches made for musl are only applied on TCLIBC is musl
Signature · 1 line
1.9.1
PATCH 3/3 systemd: fix CVE-2018-15688
In reply to Chen QiBackport patch to fix the following CVE.
CVE: CVE-2018-15688
--- ...sure-we-have-enough-space-for-the-DHCP6-o.patch | 36 ++++++++++++++++++++++ meta/recipes-core/systemd/systemd_239.bb | 1 + 2 files changed, 37 insertions(+) create mode 100644 meta/recipes-core/systemd/systemd/0001-dhcp6-make-sure-we-have-enough-space-for-the-DHCP6-o.patch
meta/recipes-core/systemd/systemd/0001-dhcp6-make-sure-we-have-enough-space-for-the-DHCP6-o.patch new file +36 -0
@@ -0,0 +1,36 @@ +From a6af1af8b8fa887533b048f74a6c932d99d204ed Mon Sep 17 00:00:00 2001 +From: Lennart Poettering <[email protected]> +Date: Fri, 19 Oct 2018 12:12:33 +0200 +Subject: [PATCH] dhcp6: make sure we have enough space for the DHCP6 option + header + +Fixes a vulnerability originally discovered by Felix Wilhelm from +Google. + +CVE-2018-15688 +LP: #1795921 +https://bugzilla.redhat.com/show_bug.cgi?id=1639067 + +Upstream-Status: Backport + +Signed-off-by: Chen Qi <[email protected]> +--- + src/libsystemd-network/dhcp6-option.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c +index 18196b1..0979497 100644 +--- a/src/libsystemd-network/dhcp6-option.c ++++ b/src/libsystemd-network/dhcp6-option.c +@@ -103,7 +103,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { + return -EINVAL; + } + +- if (*buflen < len) ++ if (*buflen < offsetof(DHCP6Option, data) + len) + return -ENOBUFS; + + ia_hdr = *buf; +-- +2.7.4 +
meta/recipes-core/systemd/systemd_239.bb +1 -0
@@ -32,6 +32,7 @@ SRC_URI += "file://touchscreen.rules \ file://0023-resolvconf-fixes-for-the-compatibility-interface.patch \ file://0001-core-when-deserializing-state-always-use-read_line-L.patch \ file://0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch \ + file://0001-dhcp6-make-sure-we-have-enough-space-for-the-DHCP6-o.patch \ " # patches made for musl are only applied on TCLIBC is musl
Signature · 1 line
1.9.1
✗ patchtest: failure for systemd: backport patches to fix 3 CVEs
In reply to Chen Qi== Series Details ==
Series: systemd: backport patches to fix 3 CVEs
Revision: 1
URL : https://patchwork.openembedded.org/series/14759/
State : failure
== Summary ==
Thank you for submitting this patch series to OpenEmbedded Core. This is an automated response. Several tests have been executed on the proposed series by patchtest resulting in the following failures:
* Patch [1/3] systemd: fix CVE-2018-15686 Issue Missing or incorrectly formatted CVE tag in included patch file [test_cve_tag_format] Suggested fix Correct or include the CVE tag on cve patch with format: "CVE: CVE-YYYY-XXXX"
If you believe any of these test results are incorrect, please reply to the mailing list ([email protected]) raising your concerns. Otherwise we would appreciate you correcting the issues and submitting a new version of the patchset if applicable. Please ensure you add/increment the version number when sending the new version (i.e. [PATCH] -> [PATCH v2] -> [PATCH v3] -> ...).
---
Guidelines: https://www.openembedded.org/wiki/Commit_Patch_Message_Guidelines Test framework: http://git.yoctoproject.org/cgit/cgit.cgi/patchtest Test suite: http://git.yoctoproject.org/cgit/cgit.cgi/patchtest-oe