summaryrefslogtreecommitdiffstats
path: root/meta-networking/recipes-support/dnsmasq/dnsmasq/dnsmasq-CVE-2017-14491.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-networking/recipes-support/dnsmasq/dnsmasq/dnsmasq-CVE-2017-14491.patch')
-rw-r--r--meta-networking/recipes-support/dnsmasq/dnsmasq/dnsmasq-CVE-2017-14491.patch268
1 files changed, 268 insertions, 0 deletions
diff --git a/meta-networking/recipes-support/dnsmasq/dnsmasq/dnsmasq-CVE-2017-14491.patch b/meta-networking/recipes-support/dnsmasq/dnsmasq/dnsmasq-CVE-2017-14491.patch
new file mode 100644
index 000000000..05986788d
--- /dev/null
+++ b/meta-networking/recipes-support/dnsmasq/dnsmasq/dnsmasq-CVE-2017-14491.patch
@@ -0,0 +1,268 @@
1From 8644f7c99c5e2fde6b6872a4ab820d3520f44e24 Mon Sep 17 00:00:00 2001
2From: Simon Kelley <simon@thekelleys.org.uk>
3Date: Mon, 25 Sep 2017 18:17:11 +0100
4Subject: [PATCH 1/7] Security fix, CVE-2017-14491 DNS heap buffer overflow.
5
6commit 0549c73b7ea6b22a3c49beb4d432f185a81efcbc upstream
7git://thekelleys.org.uk/dnsmasq
8
9Fix heap overflow in DNS code. This is a potentially serious
10security hole. It allows an attacker who can make DNS
11requests to dnsmasq, and who controls the contents of
12a domain, which is thereby queried, to overflow
13(by 2 bytes) a heap buffer and either crash, or
14even take control of, dnsmasq.
15
16Upstream-Status: Backport
17
18Signed-off-by: Zhang Xiao <xiao.zhang@windriver.com>
19---
20 src/dnsmasq.h | 2 +-
21 src/dnssec.c | 2 +-
22 src/option.c | 2 +-
23 src/rfc1035.c | 50 +++++++++++++++++++++++++++++++++++++++++---------
24 src/rfc2131.c | 4 ++--
25 src/rfc3315.c | 4 ++--
26 src/util.c | 7 ++++++-
27 7 files changed, 54 insertions(+), 17 deletions(-)
28
29diff --git a/src/dnsmasq.h b/src/dnsmasq.h
30index 1896a64..ed5da36 100644
31--- a/src/dnsmasq.h
32+++ b/src/dnsmasq.h
33@@ -1161,7 +1161,7 @@ u32 rand32(void);
34 u64 rand64(void);
35 int legal_hostname(char *c);
36 char *canonicalise(char *s, int *nomem);
37-unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
38+unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
39 void *safe_malloc(size_t size);
40 void safe_pipe(int *fd, int read_noblock);
41 void *whine_malloc(size_t size);
42diff --git a/src/dnssec.c b/src/dnssec.c
43index 3c77c7d..f45c804 100644
44--- a/src/dnssec.c
45+++ b/src/dnssec.c
46@@ -2227,7 +2227,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
47
48 p = (unsigned char *)(header+1);
49
50- p = do_rfc1035_name(p, name);
51+ p = do_rfc1035_name(p, name, NULL);
52 *p++ = 0;
53 PUTSHORT(type, p);
54 PUTSHORT(class, p);
55diff --git a/src/option.c b/src/option.c
56index d8c57d6..0e1c326 100644
57--- a/src/option.c
58+++ b/src/option.c
59@@ -1378,7 +1378,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
60 }
61
62 p = newp;
63- end = do_rfc1035_name(p + len, dom);
64+ end = do_rfc1035_name(p + len, dom, NULL);
65 *end++ = 0;
66 len = end - p;
67 free(dom);
68diff --git a/src/rfc1035.c b/src/rfc1035.c
69index 24d08c1..78410d6 100644
70--- a/src/rfc1035.c
71+++ b/src/rfc1035.c
72@@ -1049,6 +1049,7 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog
73 return 0;
74 }
75
76+
77 int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
78 unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
79 {
80@@ -1058,12 +1059,21 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
81 unsigned short usval;
82 long lval;
83 char *sval;
84+#define CHECK_LIMIT(size) \
85+ if (limit && p + (size) > (unsigned char*)limit) \
86+ { \
87+ va_end(ap); \
88+ goto truncated; \
89+ }
90
91 if (truncp && *truncp)
92 return 0;
93-
94+
95 va_start(ap, format); /* make ap point to 1st unamed argument */
96-
97+
98+ /* nameoffset (1 or 2) + type (2) + class (2) + ttl (4) + 0 (2) */
99+ CHECK_LIMIT(12);
100+
101 if (nameoffset > 0)
102 {
103 PUTSHORT(nameoffset | 0xc000, p);
104@@ -1072,7 +1082,13 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
105 {
106 char *name = va_arg(ap, char *);
107 if (name)
108- p = do_rfc1035_name(p, name);
109+ p = do_rfc1035_name(p, name, limit);
110+ if (!p)
111+ {
112+ va_end(ap);
113+ goto truncated;
114+ }
115+
116 if (nameoffset < 0)
117 {
118 PUTSHORT(-nameoffset | 0xc000, p);
119@@ -1093,6 +1109,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
120 {
121 #ifdef HAVE_IPV6
122 case '6':
123+ CHECK_LIMIT(IN6ADDRSZ);
124 sval = va_arg(ap, char *);
125 memcpy(p, sval, IN6ADDRSZ);
126 p += IN6ADDRSZ;
127@@ -1100,36 +1117,47 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
128 #endif
129
130 case '4':
131+ CHECK_LIMIT(INADDRSZ);
132 sval = va_arg(ap, char *);
133 memcpy(p, sval, INADDRSZ);
134 p += INADDRSZ;
135 break;
136
137 case 'b':
138+ CHECK_LIMIT(1);
139 usval = va_arg(ap, int);
140 *p++ = usval;
141 break;
142
143 case 's':
144+ CHECK_LIMIT(2);
145 usval = va_arg(ap, int);
146 PUTSHORT(usval, p);
147 break;
148
149 case 'l':
150+ CHECK_LIMIT(4);
151 lval = va_arg(ap, long);
152 PUTLONG(lval, p);
153 break;
154
155 case 'd':
156- /* get domain-name answer arg and store it in RDATA field */
157- if (offset)
158- *offset = p - (unsigned char *)header;
159- p = do_rfc1035_name(p, va_arg(ap, char *));
160- *p++ = 0;
161+ /* get domain-name answer arg and store it in RDATA field */
162+ if (offset)
163+ *offset = p - (unsigned char *)header;
164+ p = do_rfc1035_name(p, va_arg(ap, char *), limit);
165+ if (!p)
166+ {
167+ va_end(ap);
168+ goto truncated;
169+ }
170+ CHECK_LIMIT(1);
171+ *p++ = 0;
172 break;
173
174 case 't':
175 usval = va_arg(ap, int);
176+ CHECK_LIMIT(usval);
177 sval = va_arg(ap, char *);
178 if (usval != 0)
179 memcpy(p, sval, usval);
180@@ -1141,20 +1169,24 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
181 usval = sval ? strlen(sval) : 0;
182 if (usval > 255)
183 usval = 255;
184+ CHECK_LIMIT(usval + 1);
185 *p++ = (unsigned char)usval;
186 memcpy(p, sval, usval);
187 p += usval;
188 break;
189 }
190
191+#undef CHECK_LIMIT
192 va_end(ap); /* clean up variable argument pointer */
193
194 j = p - sav - 2;
195- PUTSHORT(j, sav); /* Now, store real RDLength */
196+ /* this has already been checked against limit before */
197+ PUTSHORT(j, sav); /* Now, store real RDLength */
198
199 /* check for overflow of buffer */
200 if (limit && ((unsigned char *)limit - p) < 0)
201 {
202+truncated:
203 if (truncp)
204 *truncp = 1;
205 return 0;
206diff --git a/src/rfc2131.c b/src/rfc2131.c
207index b7c167e..0dffd36 100644
208--- a/src/rfc2131.c
209+++ b/src/rfc2131.c
210@@ -2419,10 +2419,10 @@ static void do_options(struct dhcp_context *context,
211
212 if (fqdn_flags & 0x04)
213 {
214- p = do_rfc1035_name(p, hostname);
215+ p = do_rfc1035_name(p, hostname, NULL);
216 if (domain)
217 {
218- p = do_rfc1035_name(p, domain);
219+ p = do_rfc1035_name(p, domain, NULL);
220 *p++ = 0;
221 }
222 }
223diff --git a/src/rfc3315.c b/src/rfc3315.c
224index 3f4d69c..73bdee4 100644
225--- a/src/rfc3315.c
226+++ b/src/rfc3315.c
227@@ -1472,10 +1472,10 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
228 if ((p = expand(len + 2)))
229 {
230 *(p++) = state->fqdn_flags;
231- p = do_rfc1035_name(p, state->hostname);
232+ p = do_rfc1035_name(p, state->hostname, NULL);
233 if (state->send_domain)
234 {
235- p = do_rfc1035_name(p, state->send_domain);
236+ p = do_rfc1035_name(p, state->send_domain, NULL);
237 *p = 0;
238 }
239 }
240diff --git a/src/util.c b/src/util.c
241index 93b24f5..a377e6f 100644
242--- a/src/util.c
243+++ b/src/util.c
244@@ -218,15 +218,20 @@ char *canonicalise(char *in, int *nomem)
245 return ret;
246 }
247
248-unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
249+unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
250 {
251 int j;
252
253 while (sval && *sval)
254 {
255+ if (limit && p + 1 > (unsigned char*)limit)
256+ return p;
257+
258 unsigned char *cp = p++;
259 for (j = 0; *sval && (*sval != '.'); sval++, j++)
260 {
261+ if (limit && p + 1 > (unsigned char*)limit)
262+ return p;
263 #ifdef HAVE_DNSSEC
264 if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
265 *p++ = (*(++sval))-1;
266--
2672.11.0
268