aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
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 /net/ipv6
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>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/tcp_ipv6.c127
1 files changed, 83 insertions, 44 deletions
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};