aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-04-12 14:07:47 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-12 15:25:41 -0400
commitd14a489a411937fb9420fe2b05168ee9e1e06c9c (patch)
tree1284608cf158d4b47a9aa877c8ee6a450fa502a0
parent3619eb8541a6548f6e27b75aaa96cd53c4d9f3ef (diff)
act_csum: fix possible use after free
tcf_csum_skb_nextlayer() / pskb_may_pull() can change skb->head, so we must be careful not keeping pointers to previous headers. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Grégoire Baron <baronchon@n7mm.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/act_csum.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c
index 08fa1e8a4ca4..3a4c0caa1f7d 100644
--- a/net/sched/act_csum.c
+++ b/net/sched/act_csum.c
@@ -166,15 +166,17 @@ static int tcf_csum_ipv4_igmp(struct sk_buff *skb,
166 return 1; 166 return 1;
167} 167}
168 168
169static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h, 169static int tcf_csum_ipv6_icmp(struct sk_buff *skb,
170 unsigned int ihl, unsigned int ipl) 170 unsigned int ihl, unsigned int ipl)
171{ 171{
172 struct icmp6hdr *icmp6h; 172 struct icmp6hdr *icmp6h;
173 const struct ipv6hdr *ip6h;
173 174
174 icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h)); 175 icmp6h = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*icmp6h));
175 if (icmp6h == NULL) 176 if (icmp6h == NULL)
176 return 0; 177 return 0;
177 178
179 ip6h = ipv6_hdr(skb);
178 icmp6h->icmp6_cksum = 0; 180 icmp6h->icmp6_cksum = 0;
179 skb->csum = csum_partial(icmp6h, ipl - ihl, 0); 181 skb->csum = csum_partial(icmp6h, ipl - ihl, 0);
180 icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, 182 icmp6h->icmp6_cksum = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
@@ -186,15 +188,17 @@ static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h,
186 return 1; 188 return 1;
187} 189}
188 190
189static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph, 191static int tcf_csum_ipv4_tcp(struct sk_buff *skb,
190 unsigned int ihl, unsigned int ipl) 192 unsigned int ihl, unsigned int ipl)
191{ 193{
192 struct tcphdr *tcph; 194 struct tcphdr *tcph;
195 const struct iphdr *iph;
193 196
194 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); 197 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
195 if (tcph == NULL) 198 if (tcph == NULL)
196 return 0; 199 return 0;
197 200
201 iph = ip_hdr(skb);
198 tcph->check = 0; 202 tcph->check = 0;
199 skb->csum = csum_partial(tcph, ipl - ihl, 0); 203 skb->csum = csum_partial(tcph, ipl - ihl, 0);
200 tcph->check = tcp_v4_check(ipl - ihl, 204 tcph->check = tcp_v4_check(ipl - ihl,
@@ -205,15 +209,17 @@ static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph,
205 return 1; 209 return 1;
206} 210}
207 211
208static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h, 212static int tcf_csum_ipv6_tcp(struct sk_buff *skb,
209 unsigned int ihl, unsigned int ipl) 213 unsigned int ihl, unsigned int ipl)
210{ 214{
211 struct tcphdr *tcph; 215 struct tcphdr *tcph;
216 const struct ipv6hdr *ip6h;
212 217
213 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); 218 tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph));
214 if (tcph == NULL) 219 if (tcph == NULL)
215 return 0; 220 return 0;
216 221
222 ip6h = ipv6_hdr(skb);
217 tcph->check = 0; 223 tcph->check = 0;
218 skb->csum = csum_partial(tcph, ipl - ihl, 0); 224 skb->csum = csum_partial(tcph, ipl - ihl, 0);
219 tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, 225 tcph->check = csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
@@ -225,10 +231,11 @@ static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h,
225 return 1; 231 return 1;
226} 232}
227 233
228static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph, 234static int tcf_csum_ipv4_udp(struct sk_buff *skb,
229 unsigned int ihl, unsigned int ipl, int udplite) 235 unsigned int ihl, unsigned int ipl, int udplite)
230{ 236{
231 struct udphdr *udph; 237 struct udphdr *udph;
238 const struct iphdr *iph;
232 u16 ul; 239 u16 ul;
233 240
234 /* 241 /*
@@ -242,6 +249,7 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph,
242 if (udph == NULL) 249 if (udph == NULL)
243 return 0; 250 return 0;
244 251
252 iph = ip_hdr(skb);
245 ul = ntohs(udph->len); 253 ul = ntohs(udph->len);
246 254
247 if (udplite || udph->check) { 255 if (udplite || udph->check) {
@@ -276,10 +284,11 @@ ignore_obscure_skb:
276 return 1; 284 return 1;
277} 285}
278 286
279static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h, 287static int tcf_csum_ipv6_udp(struct sk_buff *skb,
280 unsigned int ihl, unsigned int ipl, int udplite) 288 unsigned int ihl, unsigned int ipl, int udplite)
281{ 289{
282 struct udphdr *udph; 290 struct udphdr *udph;
291 const struct ipv6hdr *ip6h;
283 u16 ul; 292 u16 ul;
284 293
285 /* 294 /*
@@ -293,6 +302,7 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h,
293 if (udph == NULL) 302 if (udph == NULL)
294 return 0; 303 return 0;
295 304
305 ip6h = ipv6_hdr(skb);
296 ul = ntohs(udph->len); 306 ul = ntohs(udph->len);
297 307
298 udph->check = 0; 308 udph->check = 0;
@@ -328,7 +338,7 @@ ignore_obscure_skb:
328 338
329static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags) 339static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
330{ 340{
331 struct iphdr *iph; 341 const struct iphdr *iph;
332 int ntkoff; 342 int ntkoff;
333 343
334 ntkoff = skb_network_offset(skb); 344 ntkoff = skb_network_offset(skb);
@@ -353,19 +363,19 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
353 break; 363 break;
354 case IPPROTO_TCP: 364 case IPPROTO_TCP:
355 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP) 365 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
356 if (!tcf_csum_ipv4_tcp(skb, iph, iph->ihl * 4, 366 if (!tcf_csum_ipv4_tcp(skb, iph->ihl * 4,
357 ntohs(iph->tot_len))) 367 ntohs(iph->tot_len)))
358 goto fail; 368 goto fail;
359 break; 369 break;
360 case IPPROTO_UDP: 370 case IPPROTO_UDP:
361 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP) 371 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
362 if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4, 372 if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
363 ntohs(iph->tot_len), 0)) 373 ntohs(iph->tot_len), 0))
364 goto fail; 374 goto fail;
365 break; 375 break;
366 case IPPROTO_UDPLITE: 376 case IPPROTO_UDPLITE:
367 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE) 377 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
368 if (!tcf_csum_ipv4_udp(skb, iph, iph->ihl * 4, 378 if (!tcf_csum_ipv4_udp(skb, iph->ihl * 4,
369 ntohs(iph->tot_len), 1)) 379 ntohs(iph->tot_len), 1))
370 goto fail; 380 goto fail;
371 break; 381 break;
@@ -377,7 +387,7 @@ static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags)
377 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) 387 pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
378 goto fail; 388 goto fail;
379 389
380 ip_send_check(iph); 390 ip_send_check(ip_hdr(skb));
381 } 391 }
382 392
383 return 1; 393 return 1;
@@ -456,6 +466,7 @@ static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
456 ixhl = ipv6_optlen(ip6xh); 466 ixhl = ipv6_optlen(ip6xh);
457 if (!pskb_may_pull(skb, hl + ixhl + ntkoff)) 467 if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
458 goto fail; 468 goto fail;
469 ip6xh = (void *)(skb_network_header(skb) + hl);
459 if ((nexthdr == NEXTHDR_HOP) && 470 if ((nexthdr == NEXTHDR_HOP) &&
460 !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl))) 471 !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
461 goto fail; 472 goto fail;
@@ -464,25 +475,25 @@ static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
464 break; 475 break;
465 case IPPROTO_ICMPV6: 476 case IPPROTO_ICMPV6:
466 if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP) 477 if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
467 if (!tcf_csum_ipv6_icmp(skb, ip6h, 478 if (!tcf_csum_ipv6_icmp(skb,
468 hl, pl + sizeof(*ip6h))) 479 hl, pl + sizeof(*ip6h)))
469 goto fail; 480 goto fail;
470 goto done; 481 goto done;
471 case IPPROTO_TCP: 482 case IPPROTO_TCP:
472 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP) 483 if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
473 if (!tcf_csum_ipv6_tcp(skb, ip6h, 484 if (!tcf_csum_ipv6_tcp(skb,
474 hl, pl + sizeof(*ip6h))) 485 hl, pl + sizeof(*ip6h)))
475 goto fail; 486 goto fail;
476 goto done; 487 goto done;
477 case IPPROTO_UDP: 488 case IPPROTO_UDP:
478 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP) 489 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
479 if (!tcf_csum_ipv6_udp(skb, ip6h, hl, 490 if (!tcf_csum_ipv6_udp(skb, hl,
480 pl + sizeof(*ip6h), 0)) 491 pl + sizeof(*ip6h), 0))
481 goto fail; 492 goto fail;
482 goto done; 493 goto done;
483 case IPPROTO_UDPLITE: 494 case IPPROTO_UDPLITE:
484 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE) 495 if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
485 if (!tcf_csum_ipv6_udp(skb, ip6h, hl, 496 if (!tcf_csum_ipv6_udp(skb, hl,
486 pl + sizeof(*ip6h), 1)) 497 pl + sizeof(*ip6h), 1))
487 goto fail; 498 goto fail;
488 goto done; 499 goto done;