[arch-commits] Commit in dnsmasq/trunk (2 files)
Christian Hesse
eworm at archlinux.org
Fri Jan 19 14:06:00 UTC 2018
Date: Friday, January 19, 2018 @ 14:05:59
Author: eworm
Revision: 315151
upgpkg: dnsmasq 2.78-2
* fix locale path in build
* DNSSEC fix for wildcard NSEC records (CVE-2017-15107)
Added:
dnsmasq/trunk/0001-DNSSEC-fix-for-wildcard-NSEC-records.patch
Modified:
dnsmasq/trunk/PKGBUILD
-------------------------------------------------+
0001-DNSSEC-fix-for-wildcard-NSEC-records.patch | 203 ++++++++++++++++++++++
PKGBUILD | 16 +
2 files changed, 217 insertions(+), 2 deletions(-)
Added: 0001-DNSSEC-fix-for-wildcard-NSEC-records.patch
===================================================================
--- 0001-DNSSEC-fix-for-wildcard-NSEC-records.patch (rev 0)
+++ 0001-DNSSEC-fix-for-wildcard-NSEC-records.patch 2018-01-19 14:05:59 UTC (rev 315151)
@@ -0,0 +1,203 @@
+From 4fe6744a220eddd3f1749b40cac3dfc510787de6 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon at thekelleys.org.uk>
+Date: Fri, 19 Jan 2018 12:26:08 +0000
+Subject: DNSSEC fix for wildcard NSEC records. CVE-2017-15107 applies.
+
+It's OK for NSEC records to be expanded from wildcards,
+but in that case, the proof of non-existence is only valid
+starting at the wildcard name, *.<domain> NOT the name expanded
+from the wildcard. Without this check it's possible for an
+attacker to craft an NSEC which wrongly proves non-existence
+in a domain which includes a wildcard for NSEC.
+---
+ src/dnssec.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 114 insertions(+), 15 deletions(-)
+
+diff --git a/src/dnssec.c b/src/dnssec.c
+index eb6c11c..a54a0b4 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -103,15 +103,17 @@ static void from_wire(char *name)
+ static int count_labels(char *name)
+ {
+ int i;
+-
++ char *p;
++
+ if (*name == 0)
+ return 0;
+
+- for (i = 0; *name; name++)
+- if (*name == '.')
++ for (p = name, i = 0; *p; p++)
++ if (*p == '.')
+ i++;
+
+- return i+1;
++ /* Don't count empty first label. */
++ return *name == '.' ? i : i+1;
+ }
+
+ /* Implement RFC1982 wrapped compare for 32-bit numbers */
+@@ -1094,8 +1096,8 @@ static int hostname_cmp(const char *a, const char *b)
+ }
+ }
+
+-static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
+- char *workspace1, char *workspace2, char *name, int type, int *nons)
++static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
++ char *workspace1_in, char *workspace2, char *name, int type, int *nons)
+ {
+ int i, rc, rdlen;
+ unsigned char *p, *psave;
+@@ -1108,6 +1110,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
+ /* Find NSEC record that proves name doesn't exist */
+ for (i = 0; i < nsec_count; i++)
+ {
++ char *workspace1 = workspace1_in;
++ int sig_labels, name_labels;
++
+ p = nsecs[i];
+ if (!extract_name(header, plen, &p, workspace1, 1, 10))
+ return 0;
+@@ -1116,7 +1121,27 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
+ psave = p;
+ if (!extract_name(header, plen, &p, workspace2, 1, 10))
+ return 0;
+-
++
++ /* If NSEC comes from wildcard expansion, use original wildcard
++ as name for computation. */
++ sig_labels = *labels[i];
++ name_labels = count_labels(workspace1);
++
++ if (sig_labels < name_labels)
++ {
++ int k;
++ for (k = name_labels - sig_labels; k != 0; k--)
++ {
++ while (*workspace1 != '.' && *workspace1 != 0)
++ workspace1++;
++ if (k != 1 && *workspace1 == '.')
++ workspace1++;
++ }
++
++ workspace1--;
++ *workspace1 = '*';
++ }
++
+ rc = hostname_cmp(workspace1, name);
+
+ if (rc == 0)
+@@ -1514,24 +1539,26 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
+
+ static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
+ {
+- static unsigned char **nsecset = NULL;
+- static int nsecset_sz = 0;
++ static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
++ static int nsecset_sz = 0, rrsig_labels_sz = 0;
+
+ int type_found = 0;
+- unsigned char *p = skip_questions(header, plen);
++ unsigned char *auth_start, *p = skip_questions(header, plen);
+ int type, class, rdlen, i, nsecs_found;
+
+ /* Move to NS section */
+ if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
+ return 0;
++
++ auth_start = p;
+
+ for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
+ {
+ unsigned char *pstart = p;
+
+- if (!(p = skip_name(p, header, plen, 10)))
++ if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
+ return 0;
+-
++
+ GETSHORT(type, p);
+ GETSHORT(class, p);
+ p += 4; /* TTL */
+@@ -1548,7 +1575,69 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
+ if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
+ return 0;
+
+- nsecset[nsecs_found++] = pstart;
++ if (type == T_NSEC)
++ {
++ /* If we're looking for NSECs, find the corresponding SIGs, to
++ extract the labels value, which we need in case the NSECs
++ are the result of wildcard expansion.
++ Note that the NSEC may not have been validated yet
++ so if there are multiple SIGs, make sure the label value
++ is the same in all, to avoid be duped by a rogue one.
++ If there are no SIGs, that's an error */
++ unsigned char *p1 = auth_start;
++ int res, j, rdlen1, type1, class1;
++
++ if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
++ return 0;
++
++ rrsig_labels[nsecs_found] = NULL;
++
++ for (j = ntohs(header->nscount); j != 0; j--)
++ {
++ if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
++ return 0;
++
++ GETSHORT(type1, p1);
++ GETSHORT(class1, p1);
++ p1 += 4; /* TTL */
++ GETSHORT(rdlen1, p1);
++
++ if (!CHECK_LEN(header, p1, plen, rdlen1))
++ return 0;
++
++ if (res == 1 && class1 == qclass && type1 == T_RRSIG)
++ {
++ int type_covered;
++ unsigned char *psav = p1;
++
++ if (rdlen < 18)
++ return 0; /* bad packet */
++
++ GETSHORT(type_covered, p1);
++
++ if (type_covered == T_NSEC)
++ {
++ p1++; /* algo */
++
++ /* labels field must be the same in every SIG we find. */
++ if (!rrsig_labels[nsecs_found])
++ rrsig_labels[nsecs_found] = p1;
++ else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
++ return 0;
++ }
++ p1 = psav;
++ }
++
++ if (!ADD_RDLEN(header, p1, plen, rdlen1))
++ return 0;
++ }
++
++ /* Must have found at least one sig. */
++ if (!rrsig_labels[nsecs_found])
++ return 0;
++ }
++
++ nsecset[nsecs_found++] = pstart;
+ }
+
+ if (!ADD_RDLEN(header, p, plen, rdlen))
+@@ -1556,7 +1645,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
+ }
+
+ if (type_found == T_NSEC)
+- return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
++ return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
+ else if (type_found == T_NSEC3)
+ return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
+ else
Modified: PKGBUILD
===================================================================
--- PKGBUILD 2018-01-19 14:04:38 UTC (rev 315150)
+++ PKGBUILD 2018-01-19 14:05:59 UTC (rev 315151)
@@ -6,7 +6,7 @@
pkgname=dnsmasq
pkgver=2.78
-pkgrel=1
+pkgrel=2
pkgdesc="Lightweight, easy to configure DNS forwarder and DHCP server"
url="http://www.thekelleys.org.uk/dnsmasq/doc.html"
arch=('x86_64')
@@ -15,15 +15,23 @@
backup=('etc/dnsmasq.conf')
validpgpkeys=('D6EACBD6EE46B834248D111215CDDA6AE19135A2') # Simon Kelley <simon at thekelleys.org.uk>
source=("http://www.thekelleys.org.uk/$pkgname/$pkgname-$pkgver.tar.xz"{,.asc}
+ '0001-DNSSEC-fix-for-wildcard-NSEC-records.patch'
'dnsmasq-sysusers.conf'
'dnsmasq.service')
sha256sums=('89949f438c74b0c7543f06689c319484bd126cc4b1f8c745c742ab397681252b'
'SKIP'
+ '2fe981f3eb947407fc48cc92509823d68416390137ddab3fe35e1dda454d85f0'
'7f6ff6a709038ae580758f4b6a754451d7f7ce22957b88a36b97f7b643d3c2ab'
'983a3c7a68ce114cf7b44f0d9c59b74c266647a9e5ac34c1d1d5161610bc57fe')
_build_copts="-DHAVE_DNSSEC -DHAVE_DBUS -DHAVE_IDN -DHAVE_CONNTRACK"
+prepare() {
+ cd "$pkgname-$pkgver"
+
+ patch -Np1 < "${srcdir}"/0001-DNSSEC-fix-for-wildcard-NSEC-records.patch
+}
+
build() {
cd "$pkgname-$pkgver"
@@ -31,6 +39,8 @@
CFLAGS="$CPPFLAGS $CFLAGS" \
LDFLAGS="$LDFLAGS" \
COPTS="$_build_copts" \
+ PREFIX=/usr \
+ BINDIR=/usr/bin \
all-i18n
}
@@ -40,7 +50,9 @@
# need to pass COPTS here to avoid rebuilding the binary.
make \
COPTS="$_build_copts" \
- BINDIR=/usr/bin PREFIX=/usr DESTDIR="$pkgdir" \
+ PREFIX=/usr \
+ BINDIR=/usr/bin \
+ DESTDIR="$pkgdir" \
install install-i18n
install -Dm644 "dbus/dnsmasq.conf" "$pkgdir"/usr/share/dbus-1/system.d/dnsmasq.conf
More information about the arch-commits
mailing list