Am 10.03.19 um 16:55 schrieb Michael Biebl: > I'd like to make a stable upload for systemd, fixing 5 separate issues. > Two of them have a CVE.
... > The fix for CVE-2018-15686/#912005 is the most invasive one. I based it > partially on what was uploaded to old-stable by the debian-lts team. > With this patch applied, the demo exploit from [1] no longer causes > systemctl stop to hang. > That said, I would appreciate a second pair of eyes to look over the > patch. Sorry, forgot to attach the debdiff. Doing that now... -- Why is it that all of the instruments seeking intelligent life in the universe are pointed away from Earth?
diff --git a/debian/changelog b/debian/changelog index ecb5bc7..9adb6f5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,22 @@ +systemd (232-25+deb9u10) stretch; urgency=medium + + * journald: fix assertion failure on journal_file_link_data (Closes: #916880) + * tmpfiles: fix "e" to support shell style globs (Closes: #918400) + * mount-util: accept that name_to_handle_at() might fail with EPERM. + Container managers frequently block name_to_handle_at(), returning + EACCES or EPERM when this is issued. Accept that, and simply fall back + to fdinfo-based checks. (Closes: #917122) + * automount: ack automount requests even when already mounted. + Fixes a race condition in systemd which could result in automount requests + not being serviced and processes using them to hang, causing denial of + service. (CVE-2018-1049) + * core: when deserializing state always use read_line(…, LONG_LINE_MAX, …) + Fixes improper serialization on upgrade which can influence systemd + execution environment and lead to root privilege escalation. + (CVE-2018-15686, Closes: #912005) + + -- Michael Biebl <bi...@debian.org> Sun, 10 Mar 2019 15:52:46 +0100 + systemd (232-25+deb9u9) stretch-security; urgency=high * Non-maintainer upload by the Security Team. diff --git a/debian/patches/automount-ack-automount-requests-even-when-already-mounte.patch b/debian/patches/automount-ack-automount-requests-even-when-already-mounte.patch new file mode 100644 index 0000000..36d5ee1 --- /dev/null +++ b/debian/patches/automount-ack-automount-requests-even-when-already-mounte.patch @@ -0,0 +1,86 @@ +From: Anchor Cat <githubanchor...@anchor.net.au> +Date: Wed, 10 May 2017 21:23:58 +1000 +Subject: automount: ack automount requests even when already mounted (#5916) + +If a process accesses an autofs filesystem while systemd is in the +middle of starting the mount unit on top of it, it is possible for the +autofs_ptype_missing_direct request from the kernel to be received after +the mount unit has been fully started: + + systemd forks and execs mount ... + ... access autofs, blocks + mount exits ... + systemd receives SIGCHLD ... + ... kernel sends request + systemd receives request ... + +systemd needs to respond to this request, otherwise the kernel will +continue to block access to the mount point. + +(cherry picked from commit e7d54bf58789545a9eb0b3964233defa0b007318) +--- + src/core/automount.c | 33 ++++++++++++++++++--------------- + 1 file changed, 18 insertions(+), 15 deletions(-) + +diff --git a/src/core/automount.c b/src/core/automount.c +index f091a9a..a64374b 100644 +--- a/src/core/automount.c ++++ b/src/core/automount.c +@@ -742,8 +742,9 @@ static void automount_stop_expire(Automount *a) { + (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF); + } + +-static void automount_enter_runnning(Automount *a) { ++static void automount_enter_running(Automount *a) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; ++ Unit *trigger; + struct stat st; + int r; + +@@ -772,22 +773,24 @@ static void automount_enter_runnning(Automount *a) { + goto fail; + } + +- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) ++ /* The mount unit may have been explicitly started before we got the ++ * autofs request. Ack it to unblock anything waiting on the mount point. */ ++ if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) { + log_unit_info(UNIT(a), "Automount point already active?"); +- else { +- Unit *trigger; ++ automount_send_ready(a, a->tokens, 0); ++ return; ++ } + +- trigger = UNIT_TRIGGER(UNIT(a)); +- if (!trigger) { +- log_unit_error(UNIT(a), "Unit to trigger vanished."); +- goto fail; +- } ++ trigger = UNIT_TRIGGER(UNIT(a)); ++ if (!trigger) { ++ log_unit_error(UNIT(a), "Unit to trigger vanished."); ++ goto fail; ++ } + +- r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL); +- if (r < 0) { +- log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); +- goto fail; +- } ++ r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL); ++ if (r < 0) { ++ log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); ++ goto fail; + } + + automount_set_state(a, AUTOMOUNT_RUNNING); +@@ -1012,7 +1015,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo + goto fail; + } + +- automount_enter_runnning(a); ++ automount_enter_running(a); + break; + + case autofs_ptype_expire_direct: diff --git a/debian/patches/backport-read_line-from-systemd-master.patch b/debian/patches/backport-read_line-from-systemd-master.patch new file mode 100644 index 0000000..c77ba09 --- /dev/null +++ b/debian/patches/backport-read_line-from-systemd-master.patch @@ -0,0 +1,167 @@ +From: =?utf-8?q?Antoine_Beaupr=C3=A9?= <anar...@debian.org> +Date: Sun, 10 Mar 2019 15:04:40 +0100 +Subject: backport read_line() from systemd master + +CVE-2018-15686 requires a refactoring of fgets() to use the internal +read_line() instead, which is not present in v232. +--- + src/basic/def.h | 2 ++ + src/basic/fileio.c | 94 +++++++++++++++++++++++++++++++++++++++++++++--------- + src/basic/fileio.h | 2 ++ + 3 files changed, 83 insertions(+), 15 deletions(-) + +diff --git a/src/basic/def.h b/src/basic/def.h +index 2266eff..756ed91 100644 +--- a/src/basic/def.h ++++ b/src/basic/def.h +@@ -88,3 +88,5 @@ + "/usr/local/lib/" n "\0" \ + "/usr/lib/" n "\0" \ + _CONF_PATHS_SPLIT_USR(n) ++ ++#define LONG_LINE_MAX (1U*1024U*1024U) +diff --git a/src/basic/fileio.c b/src/basic/fileio.c +index 1615456..0652959 100644 +--- a/src/basic/fileio.c ++++ b/src/basic/fileio.c +@@ -27,6 +27,8 @@ + #include <sys/stat.h> + #include <sys/types.h> + #include <unistd.h> ++#include <stdio.h> ++#include <stdio_ext.h> + + #include "alloc-util.h" + #include "ctype.h" +@@ -47,6 +49,7 @@ + #include "time-util.h" + #include "umask-util.h" + #include "utf8.h" ++#include "def.h" + + #define READ_FULL_BYTES_MAX (4U*1024U*1024U) + +@@ -154,7 +157,7 @@ fail: + + int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; +- char t[LINE_MAX], *c; ++ int r; + + assert(fn); + assert(line); +@@ -162,22 +165,11 @@ int read_one_line_file(const char *fn, char **line) { + f = fopen(fn, "re"); + if (!f) + return -errno; ++ (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + +- if (!fgets(t, sizeof(t), f)) { +- +- if (ferror(f)) +- return errno > 0 ? -errno : -EIO; +- +- t[0] = 0; +- } +- +- c = strdup(t); +- if (!c) +- return -ENOMEM; +- truncate_nl(c); ++ r = read_line(f, LONG_LINE_MAX, line); + +- *line = c; +- return 0; ++ return r < 0 ? r : 0; + } + + int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { +@@ -1409,3 +1401,75 @@ int read_nul_string(FILE *f, char **ret) { + + return 0; + } ++ ++DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile); ++ ++int read_line(FILE *f, size_t limit, char **ret) { ++ _cleanup_free_ char *buffer = NULL; ++ size_t n = 0, allocated = 0, count = 0; ++ ++ assert(f); ++ ++ /* Something like a bounded version of getline(). ++ * ++ * Considers EOF, \n and \0 end of line delimiters, and does not include these delimiters in the string ++ * returned. ++ * ++ * Returns the number of bytes read from the files (i.e. including delimiters — this hence usually differs from ++ * the number of characters in the returned string). When EOF is hit, 0 is returned. ++ * ++ * The input parameter limit is the maximum numbers of characters in the returned string, i.e. excluding ++ * delimiters. If the limit is hit we fail and return -ENOBUFS. ++ * ++ * If a line shall be skipped ret may be initialized as NULL. */ ++ ++ if (ret) { ++ if (!GREEDY_REALLOC(buffer, allocated, 1)) ++ return -ENOMEM; ++ } ++ ++ { ++ _unused_ _cleanup_(funlockfilep) FILE *flocked = f; ++ flockfile(f); ++ ++ for (;;) { ++ int c; ++ ++ if (n >= limit) ++ return -ENOBUFS; ++ ++ errno = 0; ++ c = fgetc_unlocked(f); ++ if (c == EOF) { ++ /* if we read an error, and have no data to return, then propagate the error */ ++ if (ferror_unlocked(f) && n == 0) ++ return errno > 0 ? -errno : -EIO; ++ ++ break; ++ } ++ ++ count++; ++ ++ if (IN_SET(c, '\n', 0)) /* Reached a delimiter */ ++ break; ++ ++ if (ret) { ++ if (!GREEDY_REALLOC(buffer, allocated, n + 2)) ++ return -ENOMEM; ++ ++ buffer[n] = (char) c; ++ } ++ ++ n++; ++ } ++ } ++ ++ if (ret) { ++ buffer[n] = 0; ++ ++ *ret = buffer; ++ buffer = NULL; ++ } ++ ++ return (int) count; ++} +diff --git a/src/basic/fileio.h b/src/basic/fileio.h +index b58c83e..336491f 100644 +--- a/src/basic/fileio.h ++++ b/src/basic/fileio.h +@@ -82,6 +82,8 @@ int read_timestamp_file(const char *fn, usec_t *ret); + + int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space); + ++int read_line(FILE *f, size_t limit, char **ret); ++ + int open_tmpfile_unlinkable(const char *directory, int flags); + int open_tmpfile_linkable(const char *target, int flags, char **ret_path); + diff --git a/debian/patches/core-when-deserializing-state-always-use-read_line-LONG_L.patch b/debian/patches/core-when-deserializing-state-always-use-read_line-LONG_L.patch new file mode 100644 index 0000000..ea17dd7 --- /dev/null +++ b/debian/patches/core-when-deserializing-state-always-use-read_line-LONG_L.patch @@ -0,0 +1,176 @@ +From: Lennart Poettering <lenn...@poettering.net> +Date: Wed, 17 Oct 2018 18:36:24 +0200 +Subject: =?utf-8?q?core=3A_when_deserializing_state_always_use_read=5Fline?= + =?utf-8?q?=28=E2=80=A6=2C_LONG=5FLINE=5FMAX=2C_=E2=80=A6=29?= + +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 + +(cherry picked from commit 8948b3415d762245ebf5e19d80b97d4d8cc208c1) +--- + src/core/job.c | 19 +++++++++++-------- + src/core/manager.c | 39 +++++++++++++++++---------------------- + src/core/unit.c | 18 ++++++++---------- + 3 files changed, 36 insertions(+), 40 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index ac6910a..bd947b8 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -27,6 +27,7 @@ + #include "dbus-job.h" + #include "dbus.h" + #include "escape.h" ++#include "fileio.h" + #include "job.h" + #include "log.h" + #include "macro.h" +@@ -1020,24 +1021,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 190019c..363e221 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -2572,21 +2572,19 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + m->n_reloading++; + + for (;;) { +- char line[LINE_MAX], *l; +- +- if (!fgets(line, sizeof(line), f)) { +- if (feof(f)) +- r = 0; +- else +- r = -errno; ++ _cleanup_free_ char *line = NULL; ++ const char *l; + ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) { ++ r = log_error_errno(r, "Failed to read serialization line: %m"); + goto finish; + } ++ if (r == 0) ++ break; + +- char_array_0(line); + l = strstrip(line); +- +- if (l[0] == 0) ++ if (isempty(l)) /* end marker */ + break; + + if (startswith(l, "current-job-id=")) { +@@ -2726,21 +2724,21 @@ 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; + + /* Start marker */ +- if (!fgets(name, sizeof(name), f)) { +- if (feof(f)) +- r = 0; +- else +- r = -errno; +- ++ r = read_line(f, LONG_LINE_MAX, &line); ++ if (r < 0) { ++ r = log_error_errno(r, "Failed to read serialization line: %m"); + goto finish; + } ++ if (r == 0) ++ break; + +- char_array_0(name); ++ unit_name = strstrip(line); + +- r = manager_load_unit(m, strstrip(name), NULL, NULL, &u); ++ r = manager_load_unit(m, unit_name, NULL, NULL, &u); + if (r < 0) + goto finish; + +@@ -2750,9 +2748,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { + } + + finish: +- if (ferror(f)) +- r = -EIO; +- + assert(m->n_reloading > 0); + m->n_reloading--; + +diff --git a/src/core/unit.c b/src/core/unit.c +index 0ab6d92..34a2224 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2802,20 +2802,18 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + rt = (ExecRuntime**) ((uint8_t*) u + offset); + + 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) /* eof */ ++ break; + +- char_array_0(line); + l = strstrip(line); +- +- /* End marker */ +- if (isempty(l)) ++ if (isempty(l)) /* End marker */ + break; + + k = strcspn(l, "="); diff --git a/debian/patches/journald-fix-assertion-failure-on-journal_file_link_data..patch b/debian/patches/journald-fix-assertion-failure-on-journal_file_link_data..patch new file mode 100644 index 0000000..b5e6a1e --- /dev/null +++ b/debian/patches/journald-fix-assertion-failure-on-journal_file_link_data..patch @@ -0,0 +1,31 @@ +From: Yusuke Nojima <nojima...@gmail.com> +Date: Sun, 30 Apr 2017 02:37:53 +0900 +Subject: journald: fix assertion failure on journal_file_link_data. (#5843) + +When some error occurs during the initialization of JournalFile, +the JournalFile can be left without hash tables created. When later +trying to append an entry to that file, the assertion in +journal_file_link_data() fails, and journald crashes. + +This patch fix this issue by checking *_hash_table_size in +journal_file_verify_header(). + +(cherry picked from commit 5b3cc0c86aeddd4615e7e28e79aa89e5b77a6507) +--- + src/journal/journal-file.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index d3e0214..b6962a3 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -590,6 +590,9 @@ static int journal_file_verify_header(JournalFile *f) { + return -EBUSY; + } + ++ if (f->header->field_hash_table_size == 0 || f->header->data_hash_table_size == 0) ++ return -EBADMSG; ++ + /* Don't permit appending to files from the future. Because otherwise the realtime timestamps wouldn't + * be strictly ordered in the entries in the file anymore, and we can't have that since it breaks + * bisection. */ diff --git a/debian/patches/mount-util-accept-that-name_to_handle_at-might-fail-with-.patch b/debian/patches/mount-util-accept-that-name_to_handle_at-might-fail-with-.patch new file mode 100644 index 0000000..f1e22ff --- /dev/null +++ b/debian/patches/mount-util-accept-that-name_to_handle_at-might-fail-with-.patch @@ -0,0 +1,48 @@ +From: Lennart Poettering <lenn...@poettering.net> +Date: Wed, 1 Mar 2017 17:35:05 +0100 +Subject: mount-util: accept that name_to_handle_at() might fail with EPERM + (#5499) + +Container managers frequently block name_to_handle_at(), returning +EACCES or EPERM when this is issued. Accept that, and simply fall back +to to fdinfo-based checks. + +Note that we accept either EACCES or EPERM here, as container managers +can choose the error code and aren't very good on agreeing on just one. + +(note that this is a non-issue with nspawn, as we permit +name_to_handle_at() there, only block open_by_handle_at(), which should +be sufficiently safe). + +(cherry picked from commit 059c35f507b3efecf1b7d77e62427766f7a25b1a) +--- + src/basic/mount-util.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c +index 5d37fb4..265d5fd 100644 +--- a/src/basic/mount-util.c ++++ b/src/basic/mount-util.c +@@ -111,9 +111,10 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { + + r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { +- if (errno == ENOSYS) +- /* This kernel does not support name_to_handle_at() +- * fall back to simpler logic. */ ++ if (IN_SET(errno, ENOSYS, EACCES, EPERM)) ++ /* This kernel does not support name_to_handle_at() at all, or the syscall was blocked (maybe ++ * through seccomp, because we are running inside of a container?): fall back to simpler ++ * logic. */ + goto fallback_fdinfo; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support +@@ -162,7 +163,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { + + fallback_fdinfo: + r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); +- if (IN_SET(r, -EOPNOTSUPP, -EACCES)) ++ if (IN_SET(r, -EOPNOTSUPP, -EACCES, -EPERM)) + goto fallback_fstat; + if (r < 0) + return r; diff --git a/debian/patches/series b/debian/patches/series index d1e7804..309ca3f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -94,6 +94,12 @@ journal-do-not-remove-multiple-spaces-after-identifi.patch Refuse-dbus-message-paths-longer-than-BUS_PATH_SIZE_.patch Allocate-temporary-strings-to-hold-dbus-paths-on-the.patch sd-bus-if-we-receive-an-invalid-dbus-message-ignore-.patch +journald-fix-assertion-failure-on-journal_file_link_data..patch +tmpfiles-e-takes-globs.patch +mount-util-accept-that-name_to_handle_at-might-fail-with-.patch +automount-ack-automount-requests-even-when-already-mounte.patch +backport-read_line-from-systemd-master.patch +core-when-deserializing-state-always-use-read_line-LONG_L.patch debian/Use-Debian-specific-config-files.patch debian/don-t-try-to-start-autovt-units-when-not-running-wit.patch debian/Make-logind-hostnamed-localed-timedated-D-Bus-activa.patch diff --git a/debian/patches/tmpfiles-e-takes-globs.patch b/debian/patches/tmpfiles-e-takes-globs.patch new file mode 100644 index 0000000..eff8cb4 --- /dev/null +++ b/debian/patches/tmpfiles-e-takes-globs.patch @@ -0,0 +1,29 @@ +From: =?utf-8?q?Zbigniew_J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> +Date: Wed, 22 Nov 2017 15:16:48 +0100 +Subject: tmpfiles: "e" takes globs + +Fixes #7369. + +(cherry picked from commit 65241c1485dbad934e22544cd9d8724f4d7ff91d) +--- + src/tmpfiles/tmpfiles.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 97a564d..e139694 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1615,12 +1615,12 @@ static int clean_item(Item *i) { + case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: +- case EMPTY_DIRECTORY: + case TRUNCATE_DIRECTORY: + case IGNORE_PATH: + case COPY_FILES: + clean_item_instance(i, i->path); + return 0; ++ case EMPTY_DIRECTORY: + case IGNORE_DIRECTORY_PATH: + return glob_item(i, clean_item_instance, false); + default:
signature.asc
Description: OpenPGP digital signature