|
1 Fix for CVE-2014-3597 |
|
2 Patch: |
|
3 http://git.php.net/?p=php-src.git;a=commitdiff;h=2fefae47716d501aec41c1102f3fd4531f070b05 |
|
4 This patch was created by hand from the above community diff. |
|
5 |
|
6 |
|
7 --- php-5.2.17/ext/standard/dns.c_orig 2014-10-29 09:08:05.187565521 -0700 |
|
8 +++ php-5.2.17/ext/standard/dns.c 2014-11-04 10:54:59.065340474 -0800 |
|
9 @@ -396,8 +396,14 @@ |
|
10 #define php_dns_free_res(__res__) |
|
11 #endif |
|
12 |
|
13 +#define CHECKCP(n) do { \ |
|
14 + if (cp + n > end) { \ |
|
15 + return NULL; \ |
|
16 + } \ |
|
17 +} while (0) |
|
18 + |
|
19 /* {{{ php_parserr */ |
|
20 -static u_char *php_parserr(u_char *cp, querybuf *answer, int type_to_fetch, int store, zval **subarray) |
|
21 +static u_char *php_parserr(u_char *cp, u_char *end, querybuf *answer, int type_to_fetch, int store, zval **subarray) |
|
22 { |
|
23 u_short type, class, dlen; |
|
24 u_long ttl; |
|
25 @@ -409,16 +415,18 @@ |
|
26 |
|
27 *subarray = NULL; |
|
28 |
|
29 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, sizeof(name) - 2); |
|
30 + n = dn_expand(answer->qb2, end, cp, name, sizeof(name) - 2); |
|
31 if (n < 0) { |
|
32 return NULL; |
|
33 } |
|
34 cp += n; |
|
35 |
|
36 + CHECKCP(10); |
|
37 GETSHORT(type, cp); |
|
38 GETSHORT(class, cp); |
|
39 GETLONG(ttl, cp); |
|
40 GETSHORT(dlen, cp); |
|
41 + CHECKCP(dlen); |
|
42 if (type_to_fetch != T_ANY && type != type_to_fetch) { |
|
43 cp += dlen; |
|
44 return cp; |
|
45 @@ -435,12 +443,14 @@ |
|
46 add_assoc_string(*subarray, "host", name, 1); |
|
47 switch (type) { |
|
48 case DNS_T_A: |
|
49 + CHECKCP(4); |
|
50 add_assoc_string(*subarray, "type", "A", 1); |
|
51 snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]); |
|
52 add_assoc_string(*subarray, "ip", name, 1); |
|
53 cp += dlen; |
|
54 break; |
|
55 case DNS_T_MX: |
|
56 + CHECKCP(2); |
|
57 add_assoc_string(*subarray, "type", "MX", 1); |
|
58 GETSHORT(n, cp); |
|
59 add_assoc_long(*subarray, "pri", n); |
|
60 @@ -456,7 +466,7 @@ |
|
61 case DNS_T_PTR: |
|
62 if (type == DNS_T_PTR) |
|
63 add_assoc_string(*subarray, "type", "PTR", 1); |
|
64 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); |
|
65 + n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); |
|
66 if (n < 0) { |
|
67 return NULL; |
|
68 } |
|
69 @@ -466,51 +476,59 @@ |
|
70 case DNS_T_HINFO: |
|
71 /* See RFC 1010 for values */ |
|
72 add_assoc_string(*subarray, "type", "HINFO", 1); |
|
73 + CHECKCP(1); |
|
74 n = *cp & 0xFF; |
|
75 cp++; |
|
76 + CHECKCP(n); |
|
77 add_assoc_stringl(*subarray, "cpu", cp, n, 1); |
|
78 cp += n; |
|
79 + CHECKCP(1); |
|
80 n = *cp & 0xFF; |
|
81 cp++; |
|
82 + CHECKCP(n); |
|
83 add_assoc_stringl(*subarray, "os", cp, n, 1); |
|
84 cp += n; |
|
85 break; |
|
86 case DNS_T_TXT: |
|
87 { |
|
88 - int ll = 0; |
|
89 + int l1 = 0, l2 = 0; |
|
90 |
|
91 add_assoc_string(*subarray, "type", "TXT", 1); |
|
92 tp = emalloc(dlen + 1); |
|
93 |
|
94 - while (ll < dlen) { |
|
95 - n = cp[ll]; |
|
96 - if ((ll + n) >= dlen) { |
|
97 + while (l1 < dlen) { |
|
98 + n = cp[l1]; |
|
99 + if ((l1 + n) >= dlen) { |
|
100 // Invalid chunk length, truncate |
|
101 - n = dlen - (ll + 1); |
|
102 + n = dlen - (l1 + 1); |
|
103 } |
|
104 - memcpy(tp + ll , cp + ll + 1, n); |
|
105 - ll = ll + n + 1; |
|
106 + if (n) { |
|
107 + memcpy(tp + l2 , cp + l1 + 1, n); |
|
108 + } |
|
109 + l1 = l1 + n + 1; |
|
110 + l2 = l2 + n; |
|
111 } |
|
112 - tp[dlen] = '\0'; |
|
113 + tp[l2] = '\0'; |
|
114 cp += dlen; |
|
115 |
|
116 - add_assoc_stringl(*subarray, "txt", tp, dlen - 1, 0); |
|
117 + add_assoc_stringl(*subarray, "txt", tp, l2, 0); |
|
118 } |
|
119 break; |
|
120 case DNS_T_SOA: |
|
121 add_assoc_string(*subarray, "type", "SOA", 1); |
|
122 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2); |
|
123 + n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2); |
|
124 if (n < 0) { |
|
125 return NULL; |
|
126 } |
|
127 cp += n; |
|
128 add_assoc_string(*subarray, "mname", name, 1); |
|
129 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) -2); |
|
130 + n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2); |
|
131 if (n < 0) { |
|
132 return NULL; |
|
133 } |
|
134 cp += n; |
|
135 add_assoc_string(*subarray, "rname", name, 1); |
|
136 + CHECKCP(5*4); |
|
137 GETLONG(n, cp); |
|
138 add_assoc_long(*subarray, "serial", n); |
|
139 GETLONG(n, cp); |
|
140 @@ -524,6 +542,7 @@ |
|
141 break; |
|
142 case DNS_T_AAAA: |
|
143 tp = name; |
|
144 + CHECKCP(8*2); |
|
145 for(i=0; i < 8; i++) { |
|
146 GETSHORT(s, cp); |
|
147 if (s != 0) { |
|
148 @@ -558,6 +577,7 @@ |
|
149 case DNS_T_A6: |
|
150 p = cp; |
|
151 add_assoc_string(*subarray, "type", "A6", 1); |
|
152 + CHECKCP(1); |
|
153 n = ((int)cp[0]) & 0xFF; |
|
154 cp++; |
|
155 add_assoc_long(*subarray, "masklen", n); |
|
156 @@ -593,6 +613,7 @@ |
|
157 cp++; |
|
158 } |
|
159 for(i = (n+8)/16; i < 8; i++) { |
|
160 + CHECKCP(2); |
|
161 GETSHORT(s, cp); |
|
162 if (s != 0) { |
|
163 if (tp > (u_char *)name) { |
|
164 @@ -622,7 +643,7 @@ |
|
165 tp[0] = '\0'; |
|
166 add_assoc_string(*subarray, "ipv6", name, 1); |
|
167 if (cp < p + dlen) { |
|
168 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); |
|
169 + n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); |
|
170 if (n < 0) { |
|
171 return NULL; |
|
172 } |
|
173 @@ -631,6 +652,7 @@ |
|
174 } |
|
175 break; |
|
176 case DNS_T_SRV: |
|
177 + CHECKCP(3*2); |
|
178 add_assoc_string(*subarray, "type", "SRV", 1); |
|
179 GETSHORT(n, cp); |
|
180 add_assoc_long(*subarray, "pri", n); |
|
181 @@ -638,7 +660,7 @@ |
|
182 add_assoc_long(*subarray, "weight", n); |
|
183 GETSHORT(n, cp); |
|
184 add_assoc_long(*subarray, "port", n); |
|
185 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); |
|
186 + n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); |
|
187 if (n < 0) { |
|
188 return NULL; |
|
189 } |
|
190 @@ -646,21 +668,34 @@ |
|
191 add_assoc_string(*subarray, "target", name, 1); |
|
192 break; |
|
193 case DNS_T_NAPTR: |
|
194 + CHECKCP(2*2); |
|
195 add_assoc_string(*subarray, "type", "NAPTR", 1); |
|
196 GETSHORT(n, cp); |
|
197 add_assoc_long(*subarray, "order", n); |
|
198 GETSHORT(n, cp); |
|
199 add_assoc_long(*subarray, "pref", n); |
|
200 + |
|
201 + CHECKCP(1); |
|
202 n = (cp[0] & 0xFF); |
|
203 - add_assoc_stringl(*subarray, "flags", ++cp, n, 1); |
|
204 + cp++; |
|
205 + CHECKCP(n); |
|
206 + add_assoc_stringl(*subarray, "flags", cp, n, 1); |
|
207 cp += n; |
|
208 + |
|
209 + CHECKCP(1); |
|
210 n = (cp[0] & 0xFF); |
|
211 - add_assoc_stringl(*subarray, "services", ++cp, n, 1); |
|
212 + cp++; |
|
213 + CHECKCP(n); |
|
214 + add_assoc_stringl(*subarray, "services", cp, n, 1); |
|
215 cp += n; |
|
216 + |
|
217 + CHECKCP(1); |
|
218 n = (cp[0] & 0xFF); |
|
219 - add_assoc_stringl(*subarray, "regex", ++cp, n, 1); |
|
220 + cp++; |
|
221 + CHECKCP(n); |
|
222 + add_assoc_stringl(*subarray, "regex", cp, n, 1); |
|
223 cp += n; |
|
224 - n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); |
|
225 + n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); |
|
226 if (n < 0) { |
|
227 return NULL; |
|
228 } |
|
229 @@ -833,7 +868,7 @@ |
|
230 while (an-- && cp && cp < end) { |
|
231 zval *retval; |
|
232 |
|
233 - cp = php_parserr(cp, &answer, type_to_fetch, store_results, &retval); |
|
234 + cp = php_parserr(cp, end, &answer, type_to_fetch, store_results, &retval); |
|
235 if (retval != NULL && store_results) { |
|
236 add_next_index_zval(return_value, retval); |
|
237 } |
|
238 @@ -848,7 +883,7 @@ |
|
239 while (ns-- > 0 && cp && cp < end) { |
|
240 zval *retval; |
|
241 |
|
242 - cp = php_parserr(cp, &answer, DNS_T_ANY, 1, &retval); |
|
243 + cp = php_parserr(cp, end, &answer, DNS_T_ANY, 1, &retval); |
|
244 if (retval != NULL) { |
|
245 add_next_index_zval(authns, retval); |
|
246 } |
|
247 @@ -857,7 +892,7 @@ |
|
248 while (ar-- > 0 && cp && cp < end) { |
|
249 zval *retval; |
|
250 |
|
251 - cp = php_parserr(cp, &answer, DNS_T_ANY, 1, &retval); |
|
252 + cp = php_parserr(cp, end, &answer, DNS_T_ANY, 1, &retval); |
|
253 if (retval != NULL) { |
|
254 add_next_index_zval(addtl, retval); |
|
255 } |