aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Langley <agl@imperialviolet.org>2008-07-19 03:01:42 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-19 03:01:42 -0400
commit49a72dfb8814c2d65bd9f8c9c6daf6395a1ec58d (patch)
tree38804d609f21503573bbdd8bb9af38df99275ff5
parent845525a642c1c9e1335c33a274d4273906ee58eb (diff)
tcp: Fix MD5 signatures for non-linear skbs
Currently, the MD5 code assumes that the SKBs are linear and, in the case that they aren't, happily goes off and hashes off the end of the SKB and into random memory. Reported by Stephen Hemminger in [1]. Advice thanks to Stephen and Evgeniy Polyakov. Also includes a couple of missed route_caps from Stephen's patch in [2]. [1] http://marc.info/?l=linux-netdev&m=121445989106145&w=2 [2] http://marc.info/?l=linux-netdev&m=121459157816964&w=2 Signed-off-by: Adam Langley <agl@imperialviolet.org> Acked-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/tcp.h29
-rw-r--r--net/ipv4/tcp.c127
-rw-r--r--net/ipv4/tcp_ipv4.c140
-rw-r--r--net/ipv4/tcp_output.c14
-rw-r--r--net/ipv6/tcp_ipv6.c127
5 files changed, 242 insertions, 195 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 92d7b551dc55..31f5bbfc59bc 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1112,20 +1112,12 @@ struct tcp_md5sig_pool {
1112#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ 1112#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */
1113 1113
1114/* - functions */ 1114/* - functions */
1115extern int tcp_calc_md5_hash(char *md5_hash, 1115extern int tcp_v4_md5_hash_skb(char *md5_hash,
1116 struct tcp_md5sig_key *key, 1116 struct tcp_md5sig_key *key,
1117 int bplen, 1117 struct sock *sk,
1118 struct tcphdr *th, 1118 struct request_sock *req,
1119 unsigned int tcplen, 1119 struct sk_buff *skb);
1120 struct tcp_md5sig_pool *hp); 1120
1121
1122extern int tcp_v4_calc_md5_hash(char *md5_hash,
1123 struct tcp_md5sig_key *key,
1124 struct sock *sk,
1125 struct dst_entry *dst,
1126 struct request_sock *req,
1127 struct tcphdr *th,
1128 unsigned int tcplen);
1129extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, 1121extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
1130 struct sock *addr_sk); 1122 struct sock *addr_sk);
1131 1123
@@ -1152,6 +1144,11 @@ extern void tcp_free_md5sig_pool(void);
1152 1144
1153extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); 1145extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu);
1154extern void __tcp_put_md5sig_pool(void); 1146extern void __tcp_put_md5sig_pool(void);
1147extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *);
1148extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *,
1149 unsigned header_len);
1150extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
1151 struct tcp_md5sig_key *key);
1155 1152
1156static inline 1153static inline
1157struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) 1154struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
@@ -1381,10 +1378,8 @@ struct tcp_sock_af_ops {
1381 int (*calc_md5_hash) (char *location, 1378 int (*calc_md5_hash) (char *location,
1382 struct tcp_md5sig_key *md5, 1379 struct tcp_md5sig_key *md5,
1383 struct sock *sk, 1380 struct sock *sk,
1384 struct dst_entry *dst,
1385 struct request_sock *req, 1381 struct request_sock *req,
1386 struct tcphdr *th, 1382 struct sk_buff *skb);
1387 unsigned int len);
1388 int (*md5_add) (struct sock *sk, 1383 int (*md5_add) (struct sock *sk,
1389 struct sock *addr_sk, 1384 struct sock *addr_sk,
1390 u8 *newkey, 1385 u8 *newkey,
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 827e6132af5f..0b491bf03db4 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2465,76 +2465,6 @@ static unsigned long tcp_md5sig_users;
2465static struct tcp_md5sig_pool **tcp_md5sig_pool; 2465static struct tcp_md5sig_pool **tcp_md5sig_pool;
2466static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); 2466static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
2467 2467
2468int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
2469 int bplen,
2470 struct tcphdr *th, unsigned int tcplen,
2471 struct tcp_md5sig_pool *hp)
2472{
2473 struct scatterlist sg[4];
2474 __u16 data_len;
2475 int block = 0;
2476 __sum16 cksum;
2477 struct hash_desc *desc = &hp->md5_desc;
2478 int err;
2479 unsigned int nbytes = 0;
2480
2481 sg_init_table(sg, 4);
2482
2483 /* 1. The TCP pseudo-header */
2484 sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
2485 nbytes += bplen;
2486
2487 /* 2. The TCP header, excluding options, and assuming a
2488 * checksum of zero
2489 */
2490 cksum = th->check;
2491 th->check = 0;
2492 sg_set_buf(&sg[block++], th, sizeof(*th));
2493 nbytes += sizeof(*th);
2494
2495 /* 3. The TCP segment data (if any) */
2496 data_len = tcplen - (th->doff << 2);
2497 if (data_len > 0) {
2498 u8 *data = (u8 *)th + (th->doff << 2);
2499 sg_set_buf(&sg[block++], data, data_len);
2500 nbytes += data_len;
2501 }
2502
2503 /* 4. an independently-specified key or password, known to both
2504 * TCPs and presumably connection-specific
2505 */
2506 sg_set_buf(&sg[block++], key->key, key->keylen);
2507 nbytes += key->keylen;
2508
2509 sg_mark_end(&sg[block - 1]);
2510
2511 /* Now store the hash into the packet */
2512 err = crypto_hash_init(desc);
2513 if (err) {
2514 if (net_ratelimit())
2515 printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
2516 return -1;
2517 }
2518 err = crypto_hash_update(desc, sg, nbytes);
2519 if (err) {
2520 if (net_ratelimit())
2521 printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
2522 return -1;
2523 }
2524 err = crypto_hash_final(desc, md5_hash);
2525 if (err) {
2526 if (net_ratelimit())
2527 printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
2528 return -1;
2529 }
2530
2531 /* Reset header */
2532 th->check = cksum;
2533
2534 return 0;
2535}
2536EXPORT_SYMBOL(tcp_calc_md5_hash);
2537
2538static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) 2468static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
2539{ 2469{
2540 int cpu; 2470 int cpu;
@@ -2658,6 +2588,63 @@ void __tcp_put_md5sig_pool(void)
2658} 2588}
2659 2589
2660EXPORT_SYMBOL(__tcp_put_md5sig_pool); 2590EXPORT_SYMBOL(__tcp_put_md5sig_pool);
2591
2592int tcp_md5_hash_header(struct tcp_md5sig_pool *hp,
2593 struct tcphdr *th)
2594{
2595 struct scatterlist sg;
2596 int err;
2597
2598 __sum16 old_checksum = th->check;
2599 th->check = 0;
2600 /* options aren't included in the hash */
2601 sg_init_one(&sg, th, sizeof(struct tcphdr));
2602 err = crypto_hash_update(&hp->md5_desc, &sg, sizeof(struct tcphdr));
2603 th->check = old_checksum;
2604 return err;
2605}
2606
2607EXPORT_SYMBOL(tcp_md5_hash_header);
2608
2609int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
2610 struct sk_buff *skb, unsigned header_len)
2611{
2612 struct scatterlist sg;
2613 const struct tcphdr *tp = tcp_hdr(skb);
2614 struct hash_desc *desc = &hp->md5_desc;
2615 unsigned i;
2616 const unsigned head_data_len = skb_headlen(skb) > header_len ?
2617 skb_headlen(skb) - header_len : 0;
2618 const struct skb_shared_info *shi = skb_shinfo(skb);
2619
2620 sg_init_table(&sg, 1);
2621
2622 sg_set_buf(&sg, ((u8 *) tp) + header_len, head_data_len);
2623 if (crypto_hash_update(desc, &sg, head_data_len))
2624 return 1;
2625
2626 for (i = 0; i < shi->nr_frags; ++i) {
2627 const struct skb_frag_struct *f = &shi->frags[i];
2628 sg_set_page(&sg, f->page, f->size, f->page_offset);
2629 if (crypto_hash_update(desc, &sg, f->size))
2630 return 1;
2631 }
2632
2633 return 0;
2634}
2635
2636EXPORT_SYMBOL(tcp_md5_hash_skb_data);
2637
2638int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, struct tcp_md5sig_key *key)
2639{
2640 struct scatterlist sg;
2641
2642 sg_init_one(&sg, key->key, key->keylen);
2643 return crypto_hash_update(&hp->md5_desc, &sg, key->keylen);
2644}
2645
2646EXPORT_SYMBOL(tcp_md5_hash_key);
2647
2661#endif 2648#endif
2662 2649
2663void tcp_done(struct sock *sk) 2650void tcp_done(struct sock *sk)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 29adc668ad51..5400d75ff17a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -87,9 +87,8 @@ int sysctl_tcp_low_latency __read_mostly;
87#ifdef CONFIG_TCP_MD5SIG 87#ifdef CONFIG_TCP_MD5SIG
88static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, 88static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
89 __be32 addr); 89 __be32 addr);
90static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 90static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
91 __be32 saddr, __be32 daddr, 91 __be32 daddr, __be32 saddr, struct tcphdr *th);
92 struct tcphdr *th, unsigned int tcplen);
93#else 92#else
94static inline 93static inline
95struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) 94struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
@@ -583,11 +582,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
583 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; 582 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED;
584 rep.th.doff = arg.iov[0].iov_len / 4; 583 rep.th.doff = arg.iov[0].iov_len / 4;
585 584
586 tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[1], 585 tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1],
587 key, 586 key, ip_hdr(skb)->daddr,
588 ip_hdr(skb)->daddr, 587 ip_hdr(skb)->saddr, &rep.th);
589 ip_hdr(skb)->saddr,
590 &rep.th, arg.iov[0].iov_len);
591 } 588 }
592#endif 589#endif
593 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, 590 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -657,11 +654,9 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
657 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; 654 arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED;
658 rep.th.doff = arg.iov[0].iov_len/4; 655 rep.th.doff = arg.iov[0].iov_len/4;
659 656
660 tcp_v4_do_calc_md5_hash((__u8 *)&rep.opt[offset], 657 tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset],
661 key, 658 key, ip_hdr(skb)->daddr,
662 ip_hdr(skb)->daddr, 659 ip_hdr(skb)->saddr, &rep.th);
663 ip_hdr(skb)->saddr,
664 &rep.th, arg.iov[0].iov_len);
665 } 660 }
666#endif 661#endif
667 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, 662 arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
@@ -989,28 +984,16 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
989 newkey, cmd.tcpm_keylen); 984 newkey, cmd.tcpm_keylen);
990} 985}
991 986
992static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 987static int tcp_v4_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
993 __be32 saddr, __be32 daddr, 988 __be32 daddr, __be32 saddr, int nbytes)
994 struct tcphdr *th,
995 unsigned int tcplen)
996{ 989{
997 struct tcp_md5sig_pool *hp;
998 struct tcp4_pseudohdr *bp; 990 struct tcp4_pseudohdr *bp;
999 int err; 991 struct scatterlist sg;
1000
1001 /*
1002 * Okay, so RFC2385 is turned on for this connection,
1003 * so we need to generate the MD5 hash for the packet now.
1004 */
1005
1006 hp = tcp_get_md5sig_pool();
1007 if (!hp)
1008 goto clear_hash_noput;
1009 992
1010 bp = &hp->md5_blk.ip4; 993 bp = &hp->md5_blk.ip4;
1011 994
1012 /* 995 /*
1013 * The TCP pseudo-header (in the order: source IP address, 996 * 1. the TCP pseudo-header (in the order: source IP address,
1014 * destination IP address, zero-padded protocol number, and 997 * destination IP address, zero-padded protocol number, and
1015 * segment length) 998 * segment length)
1016 */ 999 */
@@ -1018,48 +1001,95 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
1018 bp->daddr = daddr; 1001 bp->daddr = daddr;
1019 bp->pad = 0; 1002 bp->pad = 0;
1020 bp->protocol = IPPROTO_TCP; 1003 bp->protocol = IPPROTO_TCP;
1021 bp->len = htons(tcplen); 1004 bp->len = cpu_to_be16(nbytes);
1022 1005
1023 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), 1006 sg_init_one(&sg, bp, sizeof(*bp));
1024 th, tcplen, hp); 1007 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
1025 if (err) 1008}
1009
1010static int tcp_v4_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
1011 __be32 daddr, __be32 saddr, struct tcphdr *th)
1012{
1013 struct tcp_md5sig_pool *hp;
1014 struct hash_desc *desc;
1015
1016 hp = tcp_get_md5sig_pool();
1017 if (!hp)
1018 goto clear_hash_noput;
1019 desc = &hp->md5_desc;
1020
1021 if (crypto_hash_init(desc))
1022 goto clear_hash;
1023 if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
1024 goto clear_hash;
1025 if (tcp_md5_hash_header(hp, th))
1026 goto clear_hash;
1027 if (tcp_md5_hash_key(hp, key))
1028 goto clear_hash;
1029 if (crypto_hash_final(desc, md5_hash))
1026 goto clear_hash; 1030 goto clear_hash;
1027 1031
1028 /* Free up the crypto pool */
1029 tcp_put_md5sig_pool(); 1032 tcp_put_md5sig_pool();
1030out:
1031 return 0; 1033 return 0;
1034
1032clear_hash: 1035clear_hash:
1033 tcp_put_md5sig_pool(); 1036 tcp_put_md5sig_pool();
1034clear_hash_noput: 1037clear_hash_noput:
1035 memset(md5_hash, 0, 16); 1038 memset(md5_hash, 0, 16);
1036 goto out; 1039 return 1;
1037} 1040}
1038 1041
1039int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 1042int tcp_v4_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
1040 struct sock *sk, 1043 struct sock *sk, struct request_sock *req,
1041 struct dst_entry *dst, 1044 struct sk_buff *skb)
1042 struct request_sock *req,
1043 struct tcphdr *th,
1044 unsigned int tcplen)
1045{ 1045{
1046 struct tcp_md5sig_pool *hp;
1047 struct hash_desc *desc;
1048 struct tcphdr *th = tcp_hdr(skb);
1046 __be32 saddr, daddr; 1049 __be32 saddr, daddr;
1047 1050
1048 if (sk) { 1051 if (sk) {
1049 saddr = inet_sk(sk)->saddr; 1052 saddr = inet_sk(sk)->saddr;
1050 daddr = inet_sk(sk)->daddr; 1053 daddr = inet_sk(sk)->daddr;
1054 } else if (req) {
1055 saddr = inet_rsk(req)->loc_addr;
1056 daddr = inet_rsk(req)->rmt_addr;
1051 } else { 1057 } else {
1052 struct rtable *rt = (struct rtable *)dst; 1058 const struct iphdr *iph = ip_hdr(skb);
1053 BUG_ON(!rt); 1059 saddr = iph->saddr;
1054 saddr = rt->rt_src; 1060 daddr = iph->daddr;
1055 daddr = rt->rt_dst;
1056 } 1061 }
1057 return tcp_v4_do_calc_md5_hash(md5_hash, key, 1062
1058 saddr, daddr, 1063 hp = tcp_get_md5sig_pool();
1059 th, tcplen); 1064 if (!hp)
1065 goto clear_hash_noput;
1066 desc = &hp->md5_desc;
1067
1068 if (crypto_hash_init(desc))
1069 goto clear_hash;
1070
1071 if (tcp_v4_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
1072 goto clear_hash;
1073 if (tcp_md5_hash_header(hp, th))
1074 goto clear_hash;
1075 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
1076 goto clear_hash;
1077 if (tcp_md5_hash_key(hp, key))
1078 goto clear_hash;
1079 if (crypto_hash_final(desc, md5_hash))
1080 goto clear_hash;
1081
1082 tcp_put_md5sig_pool();
1083 return 0;
1084
1085clear_hash:
1086 tcp_put_md5sig_pool();
1087clear_hash_noput:
1088 memset(md5_hash, 0, 16);
1089 return 1;
1060} 1090}
1061 1091
1062EXPORT_SYMBOL(tcp_v4_calc_md5_hash); 1092EXPORT_SYMBOL(tcp_v4_md5_hash_skb);
1063 1093
1064static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) 1094static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
1065{ 1095{
@@ -1104,10 +1134,9 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
1104 /* Okay, so this is hash_expected and hash_location - 1134 /* Okay, so this is hash_expected and hash_location -
1105 * so we need to calculate the checksum. 1135 * so we need to calculate the checksum.
1106 */ 1136 */
1107 genhash = tcp_v4_do_calc_md5_hash(newhash, 1137 genhash = tcp_v4_md5_hash_skb(newhash,
1108 hash_expected, 1138 hash_expected,
1109 iph->saddr, iph->daddr, 1139 NULL, NULL, skb);
1110 th, skb->len);
1111 1140
1112 if (genhash || memcmp(hash_location, newhash, 16) != 0) { 1141 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
1113 if (net_ratelimit()) { 1142 if (net_ratelimit()) {
@@ -1356,6 +1385,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1356 if (newkey != NULL) 1385 if (newkey != NULL)
1357 tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr, 1386 tcp_v4_md5_do_add(newsk, inet_sk(sk)->daddr,
1358 newkey, key->keylen); 1387 newkey, key->keylen);
1388 newsk->sk_route_caps &= ~NETIF_F_GSO_MASK;
1359 } 1389 }
1360#endif 1390#endif
1361 1391
@@ -1719,7 +1749,7 @@ struct inet_connection_sock_af_ops ipv4_specific = {
1719#ifdef CONFIG_TCP_MD5SIG 1749#ifdef CONFIG_TCP_MD5SIG
1720static struct tcp_sock_af_ops tcp_sock_ipv4_specific = { 1750static struct tcp_sock_af_ops tcp_sock_ipv4_specific = {
1721 .md5_lookup = tcp_v4_md5_lookup, 1751 .md5_lookup = tcp_v4_md5_lookup,
1722 .calc_md5_hash = tcp_v4_calc_md5_hash, 1752 .calc_md5_hash = tcp_v4_md5_hash_skb,
1723 .md5_add = tcp_v4_md5_add_func, 1753 .md5_add = tcp_v4_md5_add_func,
1724 .md5_parse = tcp_v4_parse_md5_keys, 1754 .md5_parse = tcp_v4_parse_md5_keys,
1725}; 1755};
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 36a19707f67f..958ff486165f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -540,8 +540,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
540 * room for it. 540 * room for it.
541 */ 541 */
542 md5 = tp->af_specific->md5_lookup(sk, sk); 542 md5 = tp->af_specific->md5_lookup(sk, sk);
543 if (md5) 543 if (md5) {
544 tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; 544 tcp_header_size += TCPOLEN_MD5SIG_ALIGNED;
545 sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
546 }
545#endif 547#endif
546 548
547 skb_push(skb, tcp_header_size); 549 skb_push(skb, tcp_header_size);
@@ -602,10 +604,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
602 /* Calculate the MD5 hash, as we have all we need now */ 604 /* Calculate the MD5 hash, as we have all we need now */
603 if (md5) { 605 if (md5) {
604 tp->af_specific->calc_md5_hash(md5_hash_location, 606 tp->af_specific->calc_md5_hash(md5_hash_location,
605 md5, 607 md5, sk, NULL, skb);
606 sk, NULL, NULL,
607 tcp_hdr(skb),
608 skb->len);
609 } 608 }
610#endif 609#endif
611 610
@@ -2264,10 +2263,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2264 /* Okay, we have all we need - do the md5 hash if needed */ 2263 /* Okay, we have all we need - do the md5 hash if needed */
2265 if (md5) { 2264 if (md5) {
2266 tp->af_specific->calc_md5_hash(md5_hash_location, 2265 tp->af_specific->calc_md5_hash(md5_hash_location,
2267 md5, 2266 md5, NULL, req, skb);
2268 NULL, dst, req,
2269 tcp_hdr(skb),
2270 skb->len);
2271 } 2267 }
2272#endif 2268#endif
2273 2269
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ca5b93a5c02a..ae45f9835014 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -736,64 +736,105 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
736 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen); 736 return tcp_v6_md5_do_add(sk, &sin6->sin6_addr, newkey, cmd.tcpm_keylen);
737} 737}
738 738
739static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 739static int tcp_v6_md5_hash_pseudoheader(struct tcp_md5sig_pool *hp,
740 struct in6_addr *saddr, 740 struct in6_addr *daddr,
741 struct in6_addr *daddr, 741 struct in6_addr *saddr, int nbytes)
742 struct tcphdr *th, unsigned int tcplen)
743{ 742{
744 struct tcp_md5sig_pool *hp;
745 struct tcp6_pseudohdr *bp; 743 struct tcp6_pseudohdr *bp;
746 int err; 744 struct scatterlist sg;
747
748 hp = tcp_get_md5sig_pool();
749 if (!hp) {
750 printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
751 goto clear_hash_noput;
752 }
753 745
754 bp = &hp->md5_blk.ip6; 746 bp = &hp->md5_blk.ip6;
755
756 /* 1. TCP pseudo-header (RFC2460) */ 747 /* 1. TCP pseudo-header (RFC2460) */
757 ipv6_addr_copy(&bp->saddr, saddr); 748 ipv6_addr_copy(&bp->saddr, saddr);
758 ipv6_addr_copy(&bp->daddr, daddr); 749 ipv6_addr_copy(&bp->daddr, daddr);
759 bp->len = htonl(tcplen); 750 bp->protocol = cpu_to_be32(IPPROTO_TCP);
760 bp->protocol = htonl(IPPROTO_TCP); 751 bp->len = cpu_to_be16(nbytes);
761 752
762 err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp), 753 sg_init_one(&sg, bp, sizeof(*bp));
763 th, tcplen, hp); 754 return crypto_hash_update(&hp->md5_desc, &sg, sizeof(*bp));
755}
764 756
765 if (err) 757static int tcp_v6_md5_hash_hdr(char *md5_hash, struct tcp_md5sig_key *key,
758 struct in6_addr *daddr, struct in6_addr *saddr,
759 struct tcphdr *th)
760{
761 struct tcp_md5sig_pool *hp;
762 struct hash_desc *desc;
763
764 hp = tcp_get_md5sig_pool();
765 if (!hp)
766 goto clear_hash_noput;
767 desc = &hp->md5_desc;
768
769 if (crypto_hash_init(desc))
770 goto clear_hash;
771 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, th->doff << 2))
772 goto clear_hash;
773 if (tcp_md5_hash_header(hp, th))
774 goto clear_hash;
775 if (tcp_md5_hash_key(hp, key))
776 goto clear_hash;
777 if (crypto_hash_final(desc, md5_hash))
766 goto clear_hash; 778 goto clear_hash;
767 779
768 /* Free up the crypto pool */
769 tcp_put_md5sig_pool(); 780 tcp_put_md5sig_pool();
770out:
771 return 0; 781 return 0;
782
772clear_hash: 783clear_hash:
773 tcp_put_md5sig_pool(); 784 tcp_put_md5sig_pool();
774clear_hash_noput: 785clear_hash_noput:
775 memset(md5_hash, 0, 16); 786 memset(md5_hash, 0, 16);
776 goto out; 787 return 1;
777} 788}
778 789
779static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, 790static int tcp_v6_md5_hash_skb(char *md5_hash, struct tcp_md5sig_key *key,
780 struct sock *sk, 791 struct sock *sk, struct request_sock *req,
781 struct dst_entry *dst, 792 struct sk_buff *skb)
782 struct request_sock *req,
783 struct tcphdr *th, unsigned int tcplen)
784{ 793{
785 struct in6_addr *saddr, *daddr; 794 struct in6_addr *saddr, *daddr;
795 struct tcp_md5sig_pool *hp;
796 struct hash_desc *desc;
797 struct tcphdr *th = tcp_hdr(skb);
786 798
787 if (sk) { 799 if (sk) {
788 saddr = &inet6_sk(sk)->saddr; 800 saddr = &inet6_sk(sk)->saddr;
789 daddr = &inet6_sk(sk)->daddr; 801 daddr = &inet6_sk(sk)->daddr;
790 } else { 802 } else if (req) {
791 saddr = &inet6_rsk(req)->loc_addr; 803 saddr = &inet6_rsk(req)->loc_addr;
792 daddr = &inet6_rsk(req)->rmt_addr; 804 daddr = &inet6_rsk(req)->rmt_addr;
805 } else {
806 struct ipv6hdr *ip6h = ipv6_hdr(skb);
807 saddr = &ip6h->saddr;
808 daddr = &ip6h->daddr;
793 } 809 }
794 return tcp_v6_do_calc_md5_hash(md5_hash, key, 810
795 saddr, daddr, 811 hp = tcp_get_md5sig_pool();
796 th, tcplen); 812 if (!hp)
813 goto clear_hash_noput;
814 desc = &hp->md5_desc;
815
816 if (crypto_hash_init(desc))
817 goto clear_hash;
818
819 if (tcp_v6_md5_hash_pseudoheader(hp, daddr, saddr, skb->len))
820 goto clear_hash;
821 if (tcp_md5_hash_header(hp, th))
822 goto clear_hash;
823 if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2))
824 goto clear_hash;
825 if (tcp_md5_hash_key(hp, key))
826 goto clear_hash;
827 if (crypto_hash_final(desc, md5_hash))
828 goto clear_hash;
829
830 tcp_put_md5sig_pool();
831 return 0;
832
833clear_hash:
834 tcp_put_md5sig_pool();
835clear_hash_noput:
836 memset(md5_hash, 0, 16);
837 return 1;
797} 838}
798 839
799static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) 840static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
@@ -834,10 +875,10 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
834 } 875 }
835 876
836 /* check the signature */ 877 /* check the signature */
837 genhash = tcp_v6_do_calc_md5_hash(newhash, 878 genhash = tcp_v6_md5_hash_skb(newhash,
838 hash_expected, 879 hash_expected,
839 &ip6h->saddr, &ip6h->daddr, 880 NULL, NULL, skb);
840 th, skb->len); 881
841 if (genhash || memcmp(hash_location, newhash, 16) != 0) { 882 if (genhash || memcmp(hash_location, newhash, 16) != 0) {
842 if (net_ratelimit()) { 883 if (net_ratelimit()) {
843 printk(KERN_INFO "MD5 Hash %s for " 884 printk(KERN_INFO "MD5 Hash %s for "
@@ -974,10 +1015,9 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
974 (TCPOPT_NOP << 16) | 1015 (TCPOPT_NOP << 16) |
975 (TCPOPT_MD5SIG << 8) | 1016 (TCPOPT_MD5SIG << 8) |
976 TCPOLEN_MD5SIG); 1017 TCPOLEN_MD5SIG);
977 tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, 1018 tcp_v6_md5_hash_hdr((__u8 *)&opt[1], key,
978 &ipv6_hdr(skb)->daddr, 1019 &ipv6_hdr(skb)->daddr,
979 &ipv6_hdr(skb)->saddr, 1020 &ipv6_hdr(skb)->saddr, t1);
980 t1, tot_len);
981 } 1021 }
982#endif 1022#endif
983 1023
@@ -1064,10 +1104,9 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
1064 if (key) { 1104 if (key) {
1065 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | 1105 *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
1066 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); 1106 (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
1067 tcp_v6_do_calc_md5_hash((__u8 *)topt, key, 1107 tcp_v6_md5_hash_hdr((__u8 *)topt, key,
1068 &ipv6_hdr(skb)->daddr, 1108 &ipv6_hdr(skb)->daddr,
1069 &ipv6_hdr(skb)->saddr, 1109 &ipv6_hdr(skb)->saddr, t1);
1070 t1, tot_len);
1071 } 1110 }
1072#endif 1111#endif
1073 1112
@@ -1783,7 +1822,7 @@ static struct inet_connection_sock_af_ops ipv6_specific = {
1783#ifdef CONFIG_TCP_MD5SIG 1822#ifdef CONFIG_TCP_MD5SIG
1784static struct tcp_sock_af_ops tcp_sock_ipv6_specific = { 1823static struct tcp_sock_af_ops tcp_sock_ipv6_specific = {
1785 .md5_lookup = tcp_v6_md5_lookup, 1824 .md5_lookup = tcp_v6_md5_lookup,
1786 .calc_md5_hash = tcp_v6_calc_md5_hash, 1825 .calc_md5_hash = tcp_v6_md5_hash_skb,
1787 .md5_add = tcp_v6_md5_add_func, 1826 .md5_add = tcp_v6_md5_add_func,
1788 .md5_parse = tcp_v6_parse_md5_keys, 1827 .md5_parse = tcp_v6_parse_md5_keys,
1789}; 1828};
@@ -1815,7 +1854,7 @@ static struct inet_connection_sock_af_ops ipv6_mapped = {
1815#ifdef CONFIG_TCP_MD5SIG 1854#ifdef CONFIG_TCP_MD5SIG
1816static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { 1855static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = {
1817 .md5_lookup = tcp_v4_md5_lookup, 1856 .md5_lookup = tcp_v4_md5_lookup,
1818 .calc_md5_hash = tcp_v4_calc_md5_hash, 1857 .calc_md5_hash = tcp_v4_md5_hash_skb,
1819 .md5_add = tcp_v6_md5_add_func, 1858 .md5_add = tcp_v6_md5_add_func,
1820 .md5_parse = tcp_v6_parse_md5_keys, 1859 .md5_parse = tcp_v6_parse_md5_keys,
1821}; 1860};