Bug 1045290 - (CVE-2017-9445) VUL-0: CVE-2017-9445: systemd-resolved: possible out-of-bounds write triggered by a specially crafted TCP payload from a DNS Server
(CVE-2017-9445)
VUL-0: CVE-2017-9445: systemd-resolved: possible out-of-bounds write triggere...
Status: RESOLVED FIXED
Classification: Novell Products
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents
unspecified
Other Other
: P3 - Medium : Major
: ---
Assigned To: Security Team bot
Security Team bot
CVSSv2:SUSE:CVE-2017-9445:6.8:(AV:N/A...
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2017-06-21 08:32 UTC by Victor Pereira
Modified: 2017-08-07 13:20 UTC (History)
4 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Victor Pereira 2017-06-21 08:32:13 UTC
Hi,

I recently discovered an out-of-bounds write in systemd-resolved in
Ubuntu, which is possible to trigger with a specially crafted TCP
payload from a DNS server.

This issue is embargoed and has not been disclosed publicly. We are
requesting a coordinated release date (CRD) of 2017-06-27 15:00 UTC. If
other members of linux-distros@vs.openwall.org do not request another
date, Ubuntu will make this bug public on the CRD.

It has been assigned CVE-2017-9445.

Details from the currently private bug follow:

https://launchpad.net/bugs/1695546

----
Certain sizes passed to dns_packet_new can cause it to allocate a buffer
that's too small. A page-aligned number - sizeof(DnsPacket)
+sizeof(iphdr) + sizeof(udphdr) will do this - so, on x86 this will be a
page-aligned number - 80. Eg, calling dns_packet_new with a size of 4016
on x86 will result in an allocation of 4096 bytes, but 108 bytes of this
are for the DnsPacket struct.

A malicious DNS server can exploit this by responding with a specially
crafted TCP payload to trick systemd-resolved in to allocating a buffer
that's too small, and subsequently write arbitrary data beyond the end
of it.
----

A patch to resolve this has been provided by Zbigniew
Jędrzejewski-Szmek, along with an additional patch to implement a test.
Both of these are attached.

Many thanks,
Chris


From c67ed7b00f62b3ea6f9476b491fd5db590d04cf4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 18 Jun 2017 15:53:15 -0400
Subject: [PATCH 1/2] test-resolved-packet: add a simple test for our
 allocation functions

---
 .gitignore                         |  1 +
 Makefile.am                        | 14 ++++++++++++
 src/resolve/meson.build            |  9 ++++++++
 src/resolve/test-resolved-packet.c | 45 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 69 insertions(+)
 create mode 100644 src/resolve/test-resolved-packet.c

diff --git a/.gitignore b/.gitignore
index 60eda2b8ce..bc47db6481 100644
--- a/.gitignore
+++ b/.gitignore
@@ -271,6 +271,7 @@
 /test-replace-var
 /test-resolve
 /test-resolve-tables
+/test-resolved-packet
 /test-ring
 /test-rlimit-util
 /test-sched-prio
diff --git a/Makefile.am b/Makefile.am
index 3b9ed874e5..59899c65cc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5748,6 +5748,7 @@ dist_zshcompletion_data += \
 tests += \
 	test-dns-packet \
 	test-resolve-tables \
+	test-resolved-packet \
 	test-dnssec
 
 manual_tests += \
@@ -5769,6 +5770,19 @@ test_resolve_tables_LDADD = \
 	$(GCRYPT_LIBS) \
 	-lm
 
+test_resolved_packet_SOURCES = \
+	src/resolve/test-resolved-packet.c \
+	$(basic_dns_sources)
+
+test_resolved_packet_CFLAGS = \
+	$(AM_CFLAGS) \
+	$(GCRYPT_CFLAGS)
+
+test_resolved_packet_LDADD = \
+	libsystemd-shared.la \
+	$(GCRYPT_LIBS) \
+	-lm
+
 test_dns_packet_SOURCES = \
 	src/resolve/test-dns-packet.c \
 	$(basic_dns_sources)
diff --git a/src/resolve/meson.build b/src/resolve/meson.build
index f3c411ffee..fe228784fa 100644
--- a/src/resolve/meson.build
+++ b/src/resolve/meson.build
@@ -160,6 +160,15 @@ tests += [
           libm],
          'ENABLE_RESOLVED'],
 
+        [['src/resolve/test-resolved-packet.c',
+          basic_dns_sources,
+          dns_type_headers],
+         [],
+         [libgcrypt,
+          libgpg_error,
+          libm],
+         'ENABLE_RESOLVED'],
+
         [['src/resolve/test-dnssec.c',
           basic_dns_sources,
           dns_type_headers],
diff --git a/src/resolve/test-resolved-packet.c b/src/resolve/test-resolved-packet.c
new file mode 100644
index 0000000000..8b7da1408d
--- /dev/null
+++ b/src/resolve/test-resolved-packet.c
@@ -0,0 +1,45 @@
+/***
+  This file is part of systemd
+
+  Copyright 2017 Zbigniew Jędrzejewski-Szmek
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "log.h"
+#include "resolved-dns-packet.h"
+
+static void test_dns_packet_new(void) {
+        size_t i;
+
+        for (i = 0; i < DNS_PACKET_SIZE_MAX + 2; i++) {
+                _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+
+                assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, i) == 0);
+
+                log_debug("dns_packet_new: %zu → %zu", i, p->allocated);
+                assert_se(p->allocated >= MIN(DNS_PACKET_SIZE_MAX, i));
+        }
+}
+
+int main(int argc, char **argv) {
+
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+        log_open();
+
+        test_dns_packet_new();
+
+        return 0;
+}
-- 
2.13.0



From 8587c3351003b1613ad2e439cebbb20fbae07e70 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 18 Jun 2017 16:07:57 -0400
Subject: [PATCH 2/2] resolved: simplify alloc size calculation

The allocation size was calculated in a complicated way, and for values
close to the page size we would actually allocate less than requested.

Reported by Chris Coulson <chris.coulson@canonical.com>.
---
 src/resolve/resolved-dns-packet.c | 8 +-------
 src/resolve/resolved-dns-packet.h | 2 --
 2 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c
index 240ee448f4..821b66e266 100644
--- a/src/resolve/resolved-dns-packet.c
+++ b/src/resolve/resolved-dns-packet.c
@@ -47,13 +47,7 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
 
         assert(ret);
 
-        if (mtu <= UDP_PACKET_HEADER_SIZE)
-                a = DNS_PACKET_SIZE_START;
-        else
-                a = mtu - UDP_PACKET_HEADER_SIZE;
-
-        if (a < DNS_PACKET_HEADER_SIZE)
-                a = DNS_PACKET_HEADER_SIZE;
+        a = MAX(mtu, DNS_PACKET_HEADER_SIZE);
 
         /* round up to next page size */
         a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h
index 2c92392e4d..3abcaf8cf3 100644
--- a/src/resolve/resolved-dns-packet.h
+++ b/src/resolve/resolved-dns-packet.h
@@ -66,8 +66,6 @@ struct DnsPacketHeader {
 /* With EDNS0 we can use larger packets, default to 4096, which is what is commonly used */
 #define DNS_PACKET_UNICAST_SIZE_LARGE_MAX 4096
 
-#define DNS_PACKET_SIZE_START 512
-
 struct DnsPacket {
         int n_ref;
         DnsProtocol protocol;
-- 
2.13.0




References:

https://launchpad.net/bugs/1695546
Comment 1 Victor Pereira 2017-06-21 08:32:42 UTC
CRD: 2017-06-27 15:00 UTC
Comment 2 Franck Bui 2017-06-21 14:16:43 UTC
Ok looks like we had a good idea to not ship resolved so far ;)

Marcus, since resolved in not shipped by any (open)SUSE distro, should we still address this issue right now or can we wait until the fix is pushed upstream ?
Comment 3 Marcus Meissner 2017-06-21 14:25:53 UTC
if we are not shipping it, the bug can be fixed when it appears upstream
Comment 5 Franck Bui 2017-06-21 14:38:16 UTC
Ok then let's wait for the fix to reach upstream and I'll backport it just in case we will enabled resolved in the future.
Comment 6 Marcus Meissner 2017-06-28 16:06:03 UTC
is now public.
Comment 7 Andreas Stieger 2017-06-28 16:10:35 UTC
public at http://seclists.org/oss-sec/2017/q2/618

Certain sizes passed to dns_packet_new can cause it to allocate a buffer
that's too small. A page-aligned number - sizeof(DnsPacket) +
sizeof(iphdr) + sizeof(udphdr) will do this - so, on x86 this will be a
page-aligned number - 80. Eg, calling dns_packet_new with a size of 4016
on x86 will result in an allocation of 4096 bytes, but 108 bytes of this
are for the DnsPacket struct.

A malicious DNS server can exploit this by responding with a specially
crafted TCP payload to trick systemd-resolved in to allocating a buffer
that's too small, and subsequently write arbitrary data beyond the end
of it.

Discoverer believes this was introduced by
https://github.com/systemd/systemd/commit/a0166609f782da91710dea9183d1bf138538db37

Upstream:
https://github.com/systemd/systemd/pull/6214
https://github.com/systemd/systemd/commit/980cb558dc0293cc387597581a130542754195a0
Comment 8 Franck Bui 2017-07-03 06:39:56 UTC
Thanks for the notification.

The fix has been backported to the affected versions (v228, v233) so this bug can be closed.

Please note that none of the openSUSE or SUSE distros are affected since systemd-resolved is not shipped.
Comment 14 Swamp Workflow Management 2017-07-19 13:11:27 UTC
SUSE-SU-2017:1898-1: An update that solves one vulnerability and has 8 fixes is now available.

Category: security (important)
Bug References: 1032029,1033238,1037120,1040153,1040968,1043900,1045290,1046750,986216
CVE References: CVE-2017-9445
Sources used:
SUSE Linux Enterprise Software Development Kit 12-SP2 (src):    systemd-228-150.7.1
SUSE Linux Enterprise Server for Raspberry Pi 12-SP2 (src):    dracut-044.1-109.8.3, systemd-228-150.7.1
SUSE Linux Enterprise Server 12-SP2 (src):    dracut-044.1-109.8.3, systemd-228-150.7.1
SUSE Linux Enterprise Desktop 12-SP2 (src):    dracut-044.1-109.8.3, systemd-228-150.7.1
OpenStack Cloud Magnum Orchestration 7 (src):    dracut-044.1-109.8.3, systemd-228-150.7.1
Comment 15 Swamp Workflow Management 2017-07-27 17:19:37 UTC
openSUSE-RU-2017:1981-1: An update that has 9 recommended fixes can now be installed.

Category: recommended (important)
Bug References: 1032029,1033238,1037120,1040153,1040968,1043900,1045290,1046750,986216
CVE References: 
Sources used:
openSUSE Leap 42.2 (src):    dracut-044.1-16.9.2, systemd-228-25.9.1, systemd-mini-228-25.9.1
Comment 16 Swamp Workflow Management 2017-07-27 17:21:21 UTC
openSUSE-RU-2017:1982-1: An update that has 11 recommended fixes can now be installed.

Category: recommended (important)
Bug References: 1032029,1032284,1033238,1037120,1040153,1040968,1043900,1045290,1046750,1048565,986216
CVE References: 
Sources used:
openSUSE Leap 42.3 (src):    dracut-044.1-23.2, systemd-228-29.1, systemd-mini-228-29.1
Comment 17 Swamp Workflow Management 2017-08-03 13:09:51 UTC
SUSE-SU-2017:2031-1: An update that solves two vulnerabilities and has 17 fixes is now available.

Category: security (moderate)
Bug References: 1004995,1029102,1029516,1032029,1033238,1036873,1037120,1038865,1040153,1040258,1040614,1040942,1040968,1043758,1043900,1045290,1046750,982303,986216
CVE References: CVE-2017-9217,CVE-2017-9445
Sources used:
SUSE Linux Enterprise Software Development Kit 12-SP3 (src):    systemd-228-150.9.3
SUSE Linux Enterprise Server 12-SP3 (src):    systemd-228-150.9.3
SUSE Linux Enterprise Desktop 12-SP3 (src):    systemd-228-150.9.3
Comment 18 Marcus Meissner 2017-08-07 13:20:05 UTC
released (even if not enabled)