aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-01-22 14:20:28 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-22 14:20:28 -0500
commit0c8729c9b914cc0360ab87171472ca7653b2aa0e (patch)
treea8b32c48effb4244f6f3e7bd6cc5252c93db9c7e /net
parentd84295067fc7e95660d84c014aa528f4409c070d (diff)
parent05ab86c55683410593720003442dde629782aaac (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== 1) The transport header did not point to the right place after esp/ah processing on tunnel mode in the receive path. As a result, the ECN field of the inner header was not set correctly, fixes from Li RongQing. 2) We did a null check too late in one of the xfrm_replay advance functions. This can lead to a division by zero, fix from Nickolai Zeldovich. 3) The size calculation of the hash table missed the muiltplication with the actual struct size when the hash table is freed. We might call the wrong free function, fix from Michal Kubecek. 4) On IPsec pmtu events we can't access the transport headers of the original packet, so force a relookup for all routes to notify about the pmtu event. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/ah4.c18
-rw-r--r--net/ipv4/esp4.c12
-rw-r--r--net/ipv4/ipcomp.c7
-rw-r--r--net/ipv6/ah6.c11
-rw-r--r--net/ipv6/esp6.c5
-rw-r--r--net/xfrm/xfrm_policy.c2
-rw-r--r--net/xfrm/xfrm_replay.c4
7 files changed, 45 insertions, 14 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index a0d8392491c3..a69b4e4a02b5 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -269,7 +269,11 @@ static void ah_input_done(struct crypto_async_request *base, int err)
269 skb->network_header += ah_hlen; 269 skb->network_header += ah_hlen;
270 memcpy(skb_network_header(skb), work_iph, ihl); 270 memcpy(skb_network_header(skb), work_iph, ihl);
271 __skb_pull(skb, ah_hlen + ihl); 271 __skb_pull(skb, ah_hlen + ihl);
272 skb_set_transport_header(skb, -ihl); 272
273 if (x->props.mode == XFRM_MODE_TUNNEL)
274 skb_reset_transport_header(skb);
275 else
276 skb_set_transport_header(skb, -ihl);
273out: 277out:
274 kfree(AH_SKB_CB(skb)->tmp); 278 kfree(AH_SKB_CB(skb)->tmp);
275 xfrm_input_resume(skb, err); 279 xfrm_input_resume(skb, err);
@@ -381,7 +385,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
381 skb->network_header += ah_hlen; 385 skb->network_header += ah_hlen;
382 memcpy(skb_network_header(skb), work_iph, ihl); 386 memcpy(skb_network_header(skb), work_iph, ihl);
383 __skb_pull(skb, ah_hlen + ihl); 387 __skb_pull(skb, ah_hlen + ihl);
384 skb_set_transport_header(skb, -ihl); 388 if (x->props.mode == XFRM_MODE_TUNNEL)
389 skb_reset_transport_header(skb);
390 else
391 skb_set_transport_header(skb, -ihl);
385 392
386 err = nexthdr; 393 err = nexthdr;
387 394
@@ -413,9 +420,12 @@ static void ah4_err(struct sk_buff *skb, u32 info)
413 if (!x) 420 if (!x)
414 return; 421 return;
415 422
416 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) 423 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
424 atomic_inc(&flow_cache_genid);
425 rt_genid_bump(net);
426
417 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0); 427 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
418 else 428 } else
419 ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0); 429 ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
420 xfrm_state_put(x); 430 xfrm_state_put(x);
421} 431}
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index b61e9deb7c7e..3b4f0cd2e63e 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -346,7 +346,10 @@ static int esp_input_done2(struct sk_buff *skb, int err)
346 346
347 pskb_trim(skb, skb->len - alen - padlen - 2); 347 pskb_trim(skb, skb->len - alen - padlen - 2);
348 __skb_pull(skb, hlen); 348 __skb_pull(skb, hlen);
349 skb_set_transport_header(skb, -ihl); 349 if (x->props.mode == XFRM_MODE_TUNNEL)
350 skb_reset_transport_header(skb);
351 else
352 skb_set_transport_header(skb, -ihl);
350 353
351 err = nexthdr[1]; 354 err = nexthdr[1];
352 355
@@ -499,9 +502,12 @@ static void esp4_err(struct sk_buff *skb, u32 info)
499 if (!x) 502 if (!x)
500 return; 503 return;
501 504
502 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) 505 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
506 atomic_inc(&flow_cache_genid);
507 rt_genid_bump(net);
508
503 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); 509 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
504 else 510 } else
505 ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0); 511 ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
506 xfrm_state_put(x); 512 xfrm_state_put(x);
507} 513}
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index d3ab47e19a89..9a46daed2f3c 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -47,9 +47,12 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
47 if (!x) 47 if (!x)
48 return; 48 return;
49 49
50 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) 50 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) {
51 atomic_inc(&flow_cache_genid);
52 rt_genid_bump(net);
53
51 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0); 54 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
52 else 55 } else
53 ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0); 56 ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
54 xfrm_state_put(x); 57 xfrm_state_put(x);
55} 58}
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index ecc35b93314b..384233188ac1 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -472,7 +472,10 @@ static void ah6_input_done(struct crypto_async_request *base, int err)
472 skb->network_header += ah_hlen; 472 skb->network_header += ah_hlen;
473 memcpy(skb_network_header(skb), work_iph, hdr_len); 473 memcpy(skb_network_header(skb), work_iph, hdr_len);
474 __skb_pull(skb, ah_hlen + hdr_len); 474 __skb_pull(skb, ah_hlen + hdr_len);
475 skb_set_transport_header(skb, -hdr_len); 475 if (x->props.mode == XFRM_MODE_TUNNEL)
476 skb_reset_transport_header(skb);
477 else
478 skb_set_transport_header(skb, -hdr_len);
476out: 479out:
477 kfree(AH_SKB_CB(skb)->tmp); 480 kfree(AH_SKB_CB(skb)->tmp);
478 xfrm_input_resume(skb, err); 481 xfrm_input_resume(skb, err);
@@ -593,9 +596,13 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
593 596
594 skb->network_header += ah_hlen; 597 skb->network_header += ah_hlen;
595 memcpy(skb_network_header(skb), work_iph, hdr_len); 598 memcpy(skb_network_header(skb), work_iph, hdr_len);
596 skb->transport_header = skb->network_header;
597 __skb_pull(skb, ah_hlen + hdr_len); 599 __skb_pull(skb, ah_hlen + hdr_len);
598 600
601 if (x->props.mode == XFRM_MODE_TUNNEL)
602 skb_reset_transport_header(skb);
603 else
604 skb_set_transport_header(skb, -hdr_len);
605
599 err = nexthdr; 606 err = nexthdr;
600 607
601out_free: 608out_free:
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 282f3723ee19..40ffd72243a4 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -300,7 +300,10 @@ static int esp_input_done2(struct sk_buff *skb, int err)
300 300
301 pskb_trim(skb, skb->len - alen - padlen - 2); 301 pskb_trim(skb, skb->len - alen - padlen - 2);
302 __skb_pull(skb, hlen); 302 __skb_pull(skb, hlen);
303 skb_set_transport_header(skb, -hdr_len); 303 if (x->props.mode == XFRM_MODE_TUNNEL)
304 skb_reset_transport_header(skb);
305 else
306 skb_set_transport_header(skb, -hdr_len);
304 307
305 err = nexthdr[1]; 308 err = nexthdr[1];
306 309
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 41eabc46f110..07c585756d2a 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2656,7 +2656,7 @@ static void xfrm_policy_fini(struct net *net)
2656 WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); 2656 WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));
2657 2657
2658 htab = &net->xfrm.policy_bydst[dir]; 2658 htab = &net->xfrm.policy_bydst[dir];
2659 sz = (htab->hmask + 1); 2659 sz = (htab->hmask + 1) * sizeof(struct hlist_head);
2660 WARN_ON(!hlist_empty(htab->table)); 2660 WARN_ON(!hlist_empty(htab->table));
2661 xfrm_hash_free(htab->table, sz); 2661 xfrm_hash_free(htab->table, sz);
2662 } 2662 }
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c
index 765f6fe951eb..35754cc8a9e5 100644
--- a/net/xfrm/xfrm_replay.c
+++ b/net/xfrm/xfrm_replay.c
@@ -242,11 +242,13 @@ static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq)
242 u32 diff; 242 u32 diff;
243 struct xfrm_replay_state_esn *replay_esn = x->replay_esn; 243 struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
244 u32 seq = ntohl(net_seq); 244 u32 seq = ntohl(net_seq);
245 u32 pos = (replay_esn->seq - 1) % replay_esn->replay_window; 245 u32 pos;
246 246
247 if (!replay_esn->replay_window) 247 if (!replay_esn->replay_window)
248 return; 248 return;
249 249
250 pos = (replay_esn->seq - 1) % replay_esn->replay_window;
251
250 if (seq > replay_esn->seq) { 252 if (seq > replay_esn->seq) {
251 diff = seq - replay_esn->seq; 253 diff = seq - replay_esn->seq;
252 254