diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2014-12-22 12:22:48 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-12-22 16:48:01 -0500 |
commit | 2dc49d1680b534877fd20cce52557ea542bb06b6 (patch) | |
tree | 888c8e5c7d12add3684c02010d1ef3902a35a4f5 /net/ipv6 | |
parent | 5ad24def21b205a8e91925cd276b0a794b5ace82 (diff) |
tcp6: don't move IP6CB before xfrm6_policy_check()
When xfrm6_policy_check() is used, _decode_session6() is called after some
intermediate functions. This function uses IP6CB(), thus TCP_SKB_CB() must be
prepared after the call of xfrm6_policy_check().
Before this patch, scenarii with IPv6 + TCP + IPsec Transport are broken.
Fixes: 971f10eca186 ("tcp: better TCP_SKB_CB layout to reduce cache line misses")
Reported-by: Huaibin Wang <huaibin.wang@6wind.com>
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 45 |
1 files changed, 29 insertions, 16 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 5ff87805258e..9c0b54e87b47 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1387,6 +1387,28 @@ ipv6_pktoptions: | |||
1387 | return 0; | 1387 | return 0; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, | ||
1391 | const struct tcphdr *th) | ||
1392 | { | ||
1393 | /* This is tricky: we move IP6CB at its correct location into | ||
1394 | * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because | ||
1395 | * _decode_session6() uses IP6CB(). | ||
1396 | * barrier() makes sure compiler won't play aliasing games. | ||
1397 | */ | ||
1398 | memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), | ||
1399 | sizeof(struct inet6_skb_parm)); | ||
1400 | barrier(); | ||
1401 | |||
1402 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | ||
1403 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | ||
1404 | skb->len - th->doff*4); | ||
1405 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | ||
1406 | TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); | ||
1407 | TCP_SKB_CB(skb)->tcp_tw_isn = 0; | ||
1408 | TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); | ||
1409 | TCP_SKB_CB(skb)->sacked = 0; | ||
1410 | } | ||
1411 | |||
1390 | static int tcp_v6_rcv(struct sk_buff *skb) | 1412 | static int tcp_v6_rcv(struct sk_buff *skb) |
1391 | { | 1413 | { |
1392 | const struct tcphdr *th; | 1414 | const struct tcphdr *th; |
@@ -1418,24 +1440,9 @@ static int tcp_v6_rcv(struct sk_buff *skb) | |||
1418 | 1440 | ||
1419 | th = tcp_hdr(skb); | 1441 | th = tcp_hdr(skb); |
1420 | hdr = ipv6_hdr(skb); | 1442 | hdr = ipv6_hdr(skb); |
1421 | /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() | ||
1422 | * barrier() makes sure compiler wont play fool^Waliasing games. | ||
1423 | */ | ||
1424 | memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), | ||
1425 | sizeof(struct inet6_skb_parm)); | ||
1426 | barrier(); | ||
1427 | |||
1428 | TCP_SKB_CB(skb)->seq = ntohl(th->seq); | ||
1429 | TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + | ||
1430 | skb->len - th->doff*4); | ||
1431 | TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); | ||
1432 | TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); | ||
1433 | TCP_SKB_CB(skb)->tcp_tw_isn = 0; | ||
1434 | TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); | ||
1435 | TCP_SKB_CB(skb)->sacked = 0; | ||
1436 | 1443 | ||
1437 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest, | 1444 | sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest, |
1438 | tcp_v6_iif(skb)); | 1445 | inet6_iif(skb)); |
1439 | if (!sk) | 1446 | if (!sk) |
1440 | goto no_tcp_socket; | 1447 | goto no_tcp_socket; |
1441 | 1448 | ||
@@ -1451,6 +1458,8 @@ process: | |||
1451 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 1458 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
1452 | goto discard_and_relse; | 1459 | goto discard_and_relse; |
1453 | 1460 | ||
1461 | tcp_v6_fill_cb(skb, hdr, th); | ||
1462 | |||
1454 | #ifdef CONFIG_TCP_MD5SIG | 1463 | #ifdef CONFIG_TCP_MD5SIG |
1455 | if (tcp_v6_inbound_md5_hash(sk, skb)) | 1464 | if (tcp_v6_inbound_md5_hash(sk, skb)) |
1456 | goto discard_and_relse; | 1465 | goto discard_and_relse; |
@@ -1482,6 +1491,8 @@ no_tcp_socket: | |||
1482 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) | 1491 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) |
1483 | goto discard_it; | 1492 | goto discard_it; |
1484 | 1493 | ||
1494 | tcp_v6_fill_cb(skb, hdr, th); | ||
1495 | |||
1485 | if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { | 1496 | if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) { |
1486 | csum_error: | 1497 | csum_error: |
1487 | TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS); | 1498 | TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS); |
@@ -1505,6 +1516,8 @@ do_time_wait: | |||
1505 | goto discard_it; | 1516 | goto discard_it; |
1506 | } | 1517 | } |
1507 | 1518 | ||
1519 | tcp_v6_fill_cb(skb, hdr, th); | ||
1520 | |||
1508 | if (skb->len < (th->doff<<2)) { | 1521 | if (skb->len < (th->doff<<2)) { |
1509 | inet_twsk_put(inet_twsk(sk)); | 1522 | inet_twsk_put(inet_twsk(sk)); |
1510 | goto bad_packet; | 1523 | goto bad_packet; |