Commit 5a96ffaf authored by Dimitri John Ledkov's avatar Dimitri John Ledkov
Browse files

releasing package systemd version 237-3ubuntu10.6

parent 1778438b
systemd (237-3ubuntu10.6) bionic-security; urgency=medium
* SECURITY UPDATE: reexec state injection
- debian/patches/CVE-2018-15686.patch: when deserializing state always use
read_line(, LONG_LINE_MAX, ) rather than fgets()
- CVE-2018-15686
* SECURITY UPDATE: chown_one() can dereference symlinks
- debian/patches/CVE-2018-15687.patch: rework recursive logic to use O_PATH
- CVE-2018-15687
* SECURITY UPDATE: symlink mishandling in systemd-tmpfiles
- debian/patches/CVE-2018-6954.patch: don't resolve pathnames when traversing
recursively through directory trees
- CVE-2018-6954
-- Chris Coulson <chris.coulson@canonical.com> Tue, 06 Nov 2018 22:32:27 +0000
systemd (237-3ubuntu10.4) bionic-security; urgency=medium
* SECURITY UPDATE: buffer overflow in dhcp6 client
- debian/patches/CVE-2018-15688.patch: make sure we have enough space
for the DHCP6 option header in src/libsystemd-network/dhcp6-option.c.
- CVE-2018-15688
-- Marc Deslauriers <marc.deslauriers@ubuntu.com> Wed, 31 Oct 2018 11:38:31 -0400
systemd (237-3ubuntu10.3) bionic; urgency=medium
* debian/extra/start-udev: Set scsi_mod scan=sync even if it's builtin
......@@ -1076,7 +1101,7 @@ systemd (233-6ubuntu2) artful; urgency=medium
systemd (233-6ubuntu1) artful; urgency=medium
Merge from Debian, existing changes:
Merge from Debian, existing changes:
* ubuntu: udev.postinst preserve virtio interfaces names on upgrades, on s390x.
New udev generates stable interface names on s390x kvm instances, however, upon
upgrades existing ethX names should be preserved to prevent breaking networking
......
From 8948b3415d762245ebf5e19d80b97d4d8cc208c1 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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
---
src/core/job.c | 19 +++++++++++--------
src/core/manager.c | 41 ++++++++++++++++++++---------------------
src/core/unit.c | 34 ++++++++++++++++++----------------
src/core/unit.h | 2 +-
4 files changed, 50 insertions(+), 46 deletions(-)
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -28,6 +28,7 @@
#include "dbus-job.h"
#include "dbus.h"
#include "escape.h"
+#include "fileio.h"
#include "job.h"
#include "log.h"
#include "macro.h"
@@ -1067,24 +1068,26 @@
}
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, "=");
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3346,21 +3346,19 @@
rt = (ExecRuntime**) ((uint8_t*) u + offset);
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, "=");
@@ -3637,23 +3635,27 @@
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;
}
}
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -689,7 +689,7 @@
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);
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -2841,22 +2841,19 @@
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;
-
+ 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 ((val = startswith(l, "current-job-id="))) {
@@ -3004,28 +3001,30 @@
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(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)
+ goto finish;
+
continue;
}
@@ -3038,9 +3037,6 @@
}
finish:
- if (ferror(f))
- r = -EIO;
-
assert(m->n_reloading > 0);
m->n_reloading--;
From 5de6cce58b3e8b79239b6e83653459d91af6e57c Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
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
---
src/core/chown-recursive.c | 146 ++++++++++++++++++-------------------
1 file changed, 70 insertions(+), 76 deletions(-)
--- a/src/core/chown-recursive.c
+++ b/src/core/chown-recursive.c
@@ -18,18 +18,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#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);
@@ -38,90 +40,82 @@
(!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;
+ d = fdopendir(fd);
+ if (!d) {
+ safe_close(fd);
+ return -errno;
+ }
- 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;
- }
+ 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;
-
- r = r > 0 || changed;
+ return r;
-finish:
- safe_close(fd);
- return r;
+ return r > 0 || changed;
}
int path_chown_recursive(const char *path, uid_t uid, gid_t gid) {
@@ -129,7 +123,7 @@
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;
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -578,3 +578,22 @@
return -EOPNOTSUPP;
}
+
+int fd_reopen(int fd, int flags) {
+ char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ int new_fd;
+
+ /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
+ * turn O_RDWR fds into O_RDONLY fds.
+ *
+ * This doesn't work on sockets (since they cannot be open()ed, ever).
+ *
+ * This implicitly resets the file read index to 0. */
+
+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+ new_fd = open(procfs_path, flags);
+ if (new_fd < 0)
+ return -errno;
+
+ return new_fd;
+}
--- a/src/basic/fd-util.h
+++ b/src/basic/fd-util.h
@@ -91,3 +91,5 @@
/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
#define ERRNO_IS_DISCONNECT(r) \
IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
+
+int fd_reopen(int fd, int flags);
From 4dac5eaba4e419b29c97da38a8b1f82336c2c892 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Fri, 19 Oct 2018 12:12:33 +0200
Subject: [PATCH 4/5] 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
---
src/libsystemd-network/dhcp6-option.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: systemd-237/src/libsystemd-network/dhcp6-option.c
===================================================================
--- systemd-237.orig/src/libsystemd-network/dhcp6-option.c 2018-10-31 11:38:26.996004319 -0400
+++ systemd-237/src/libsystemd-network/dhcp6-option.c 2018-10-31 11:38:26.988004293 -0400
@@ -118,7 +118,7 @@ int dhcp6_option_append_ia(uint8_t **buf
return -EINVAL;
}
- if (*buflen < len)
+ if (*buflen < offsetof(DHCP6Option, data) + len)
return -ENOBUFS;
ia_hdr = *buf;
This diff is collapsed.
......@@ -80,3 +80,7 @@ debian/UBUNTU-resolved-Listen-on-both-TCP-and-UDP-by-default.patch
debian/UBUNTU-networkd-if-RA-was-implicit-do-not-await-ndisc_con.patch
debian/UBUNTU-introduce-TAKE_PTR-macro.patch
debian/UBUNTU-sleep-Add-support-for-setting-a-disk-offset.patch
CVE-2018-15688.patch
CVE-2018-15686.patch
CVE-2018-15687.patch
CVE-2018-6954.patch
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment