diff options
author | Eric Dumazet <edumazet@google.com> | 2013-04-12 14:07:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-12 15:25:41 -0400 |
commit | d14a489a411937fb9420fe2b05168ee9e1e06c9c (patch) | |
tree | 1284608cf158d4b47a9aa877c8ee6a450fa502a0 /net/sched | |
parent | 3619eb8541a6548f6e27b75aaa96cd53c4d9f3ef (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>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/act_csum.c | 39 |
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 | ||
169 | static int tcf_csum_ipv6_icmp(struct sk_buff *skb, struct ipv6hdr *ip6h, | 169 | static 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 | ||
189 | static int tcf_csum_ipv4_tcp(struct sk_buff *skb, struct iphdr *iph, | 191 | static 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 | ||
208 | static int tcf_csum_ipv6_tcp(struct sk_buff *skb, struct ipv6hdr *ip6h, | 212 | static 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 | ||
228 | static int tcf_csum_ipv4_udp(struct sk_buff *skb, struct iphdr *iph, | 234 | static 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 | ||
279 | static int tcf_csum_ipv6_udp(struct sk_buff *skb, struct ipv6hdr *ip6h, | 287 | static 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 | ||
329 | static int tcf_csum_ipv4(struct sk_buff *skb, u32 update_flags) | 339 | static 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; |