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