* [PATCH] tcp: md5: fix md5 RST when both sides have listener [not found] <RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener> @ 2012-01-31 23:53 ` Shawn Lu 2012-02-01 5:09 ` Eric Dumazet 2012-02-01 8:35 ` [PATCH] tcp: md5: RST: getting md5 key from listener Shawn Lu 1 sibling, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-01-31 23:53 UTC (permalink / raw) To: eric.dumazet; +Cc: davem, netdev, xiaoclu TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp to fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listeners on both sides. md5 keys for peers are saved in listening socket. When passive side connection is gone, we can still get md5 key from listening socket. When active side of connection is gone, we can try to find listening socket through source port, and then md5 key. we are not loosing sercuriy here: packet is valified checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> --- net/ipv4/tcp_ipv4.c | 43 ++++++++++++++++++++++++++++++++++++++++--- net/ipv6/tcp_ipv6.c | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index da5d322..adafee8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -593,6 +593,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; + const __u8 *hash_location = NULL; + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; #endif struct net *net; @@ -623,9 +627,36 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_md5_do_lookup(sk, - (union tcp_md5_addr *)&ip_hdr(skb)->saddr, - AF_INET) : NULL; + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, ip_hdr(skb)->daddr, + ntohs(th->source), inet_iif(skb)); + /* don't send rst if it can't find key */ + if (!sk1) + return; + + key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, AF_INET); + if (!key) + goto release_sk1; + + genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_md5_do_lookup(sk, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, + AF_INET) : NULL; + } + if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -653,6 +684,12 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) + sock_put(sk1); +#endif } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bec41f9..00da65c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -925,6 +925,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); u32 seq = 0, ack_seq = 0; struct tcp_md5sig_key *key = NULL; +#ifdef CONFIG_TCP_MD5SIG + const __u8 *hash_location = NULL; + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; +#endif if (th->rst) return; @@ -933,8 +940,31 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) return; #ifdef CONFIG_TCP_MD5SIG - if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, &ipv6h->daddr, + ntohs(th->source), inet6_iif(skb)); + if (!sk1) + return; + + key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); + if (!key) + goto release_sk1; + + genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; + } #endif if (th->ack) @@ -944,6 +974,12 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) (th->doff << 2); tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) + sock_put(sk1); +#endif } static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 23:53 ` [PATCH] tcp: md5: fix md5 RST when both sides have listener Shawn Lu @ 2012-02-01 5:09 ` Eric Dumazet 2012-02-01 7:48 ` Shawn Lu 0 siblings, 1 reply; 19+ messages in thread From: Eric Dumazet @ 2012-02-01 5:09 UTC (permalink / raw) To: Shawn Lu; +Cc: davem, netdev, xiaoclu Le mardi 31 janvier 2012 à 15:53 -0800, Shawn Lu a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When > connection is gone, md5 key is lost, sending RST > without md5 hash is deem to ignored by peer. This can > be a problem since RST help protocal like bgp to fast > recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, > have listeners on both sides. md5 keys for peers are > saved in listening socket. When passive side connection > is gone, we can still get md5 key from listening socket. > When active side of connection is gone, we can try to > find listening socket through source port, and then md5 > key. > we are not loosing sercuriy here: > packet is valified checked with md5 hash. No RST is generated > if md5 hash doesn't match or no md5 key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- Small notes : 1) Always add [PATCH Vx] on your submission if it was a new version of a previous patch. (V2, V3, V4, ...) If possible, add after the "---" separator an explanation of what changed in your new submission : V3: added some rcu_read_lock()/rcu_read_unlock() sections 2) Also patch title and changelog are a bit confusing. Only the machine receiving the TCP message and answering by RST message needs a listener, in case tcp frame cannot be associated to an existing tcp socket (ESTABLISHED or TIMEWAIT). The other side doesnt need a listener, only a client using TCP MD5 option in its socket. Other than that, your patch seems fine to me. Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Thanks ! ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-02-01 5:09 ` Eric Dumazet @ 2012-02-01 7:48 ` Shawn Lu 2012-02-01 7:53 ` Eric Dumazet 0 siblings, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-02-01 7:48 UTC (permalink / raw) To: Eric Dumazet Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Hi, Eric: How about change the title and log to following: tcp: md5: RST: getting md5 key from listener TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp to fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listener on both side to accept connection from peer. md5 keys for peers are saved in listening socket. There are two cases in finding md5 key when connection is lost: 1.Passive receive RST: The message is send to well known port, tcp will associate packet with listener. md5 key can be gotten from listener. 2.Active receive RST (no sock): The message is send to ative side, there is no socket associated with message. In this case, finding listener from source port, then find md5 key from listener. we are not loosing sercuriy here: packet is checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Note: Will send out a new version that is on top of your new patch -- "tcp: md5: protects md5sig_info with RCU" -----Original Message----- From: Eric Dumazet [mailto:eric.dumazet@gmail.com] Sent: Tuesday, January 31, 2012 9:09 PM To: Shawn Lu Cc: davem@davemloft.net; netdev@vger.kernel.org; xiaoclu@gmail.com Subject: Re: [PATCH] tcp: md5: fix md5 RST when both sides have listener Le mardi 31 janvier 2012 à 15:53 -0800, Shawn Lu a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When connection is > gone, md5 key is lost, sending RST without md5 hash is deem to ignored > by peer. This can be a problem since RST help protocal like bgp to > fast recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, have listeners on > both sides. md5 keys for peers are saved in listening socket. When > passive side connection is gone, we can still get md5 key from > listening socket. > When active side of connection is gone, we can try to find listening > socket through source port, and then md5 key. > we are not loosing sercuriy here: > packet is valified checked with md5 hash. No RST is generated if md5 > hash doesn't match or no md5 key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- Small notes : 1) Always add [PATCH Vx] on your submission if it was a new version of a previous patch. (V2, V3, V4, ...) If possible, add after the "---" separator an explanation of what changed in your new submission : V3: added some rcu_read_lock()/rcu_read_unlock() sections 2) Also patch title and changelog are a bit confusing. Only the machine receiving the TCP message and answering by RST message needs a listener, in case tcp frame cannot be associated to an existing tcp socket (ESTABLISHED or TIMEWAIT). The other side doesnt need a listener, only a client using TCP MD5 option in its socket. Other than that, your patch seems fine to me. Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Thanks ! ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-02-01 7:48 ` Shawn Lu @ 2012-02-01 7:53 ` Eric Dumazet 2012-02-01 8:11 ` Shawn Lu 0 siblings, 1 reply; 19+ messages in thread From: Eric Dumazet @ 2012-02-01 7:53 UTC (permalink / raw) To: Shawn Lu; +Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Le mercredi 01 février 2012 à 02:48 -0500, Shawn Lu a écrit : > Hi, Eric: > > How about change the title and log to following: > > tcp: md5: RST: getting md5 key from listener > > TCP RST mechanism is broken in TCP md5(RFC2385). When > connection is gone, md5 key is lost, sending RST > without md5 hash is deem to ignored by peer. This can > be a problem since RST help protocal like bgp to fast > recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, > have listener on both side to accept connection from peer. > md5 keys for peers are saved in listening socket. > > There are two cases in finding md5 key when connection is > lost: > 1.Passive receive RST: The message is send to well known port, > tcp will associate packet with listener. md5 key can be gotten > from listener. > > 2.Active receive RST (no sock): The message is send to ative > side, there is no socket associated with message. In this case, > finding listener from source port, then find md5 key from > listener. > > we are not loosing sercuriy here: > packet is checked with md5 hash. No RST is generated > if md5 hash doesn't match or no md5 key can be found. > > Note: > Will send out a new version that is on top of your new patch > -- "tcp: md5: protects md5sig_info with RCU" > Seems good to me ! By the way, is the patch going to work if netfilter conntrack is enabled ? ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-02-01 7:53 ` Eric Dumazet @ 2012-02-01 8:11 ` Shawn Lu 2012-02-01 9:25 ` Eric Dumazet 0 siblings, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-02-01 8:11 UTC (permalink / raw) To: Eric Dumazet Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Why? Do you mean packet is droped by netfilter before getting to tcp and No RST is generated. -----Original Message----- From: Eric Dumazet [mailto:eric.dumazet@gmail.com] Sent: Tuesday, January 31, 2012 11:54 PM To: Shawn Lu Cc: davem@davemloft.net; netdev@vger.kernel.org; xiaoclu@gmail.com Subject: RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener Le mercredi 01 février 2012 à 02:48 -0500, Shawn Lu a écrit : > Hi, Eric: > > How about change the title and log to following: > > tcp: md5: RST: getting md5 key from listener > > TCP RST mechanism is broken in TCP md5(RFC2385). When > connection is gone, md5 key is lost, sending RST > without md5 hash is deem to ignored by peer. This can > be a problem since RST help protocal like bgp to fast > recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, > have listener on both side to accept connection from peer. > md5 keys for peers are saved in listening socket. > > There are two cases in finding md5 key when connection is > lost: > 1.Passive receive RST: The message is send to well known port, > tcp will associate packet with listener. md5 key can be gotten > from listener. > > 2.Active receive RST (no sock): The message is send to ative > side, there is no socket associated with message. In this case, > finding listener from source port, then find md5 key from > listener. > > we are not loosing sercuriy here: > packet is checked with md5 hash. No RST is generated > if md5 hash doesn't match or no md5 key can be found. > > Note: > Will send out a new version that is on top of your new patch > -- "tcp: md5: protects md5sig_info with RCU" > Seems good to me ! By the way, is the patch going to work if netfilter conntrack is enabled ? ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-02-01 8:11 ` Shawn Lu @ 2012-02-01 9:25 ` Eric Dumazet 0 siblings, 0 replies; 19+ messages in thread From: Eric Dumazet @ 2012-02-01 9:25 UTC (permalink / raw) To: Shawn Lu; +Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Le mercredi 01 février 2012 à 03:11 -0500, Shawn Lu a écrit : > Why? Do you mean packet is droped by netfilter before getting to tcp and No RST is generated. Hmm, net/ipv4/netfilter/ipt_REJECT.c / net/ipv6/netfilter/ip6t_REJECT.c are able to sent RST packets. I presume this is not md5 aware. ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH] tcp: md5: RST: getting md5 key from listener [not found] <RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener> 2012-01-31 23:53 ` [PATCH] tcp: md5: fix md5 RST when both sides have listener Shawn Lu @ 2012-02-01 8:35 ` Shawn Lu 2012-02-01 9:54 ` Eric Dumazet 1 sibling, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-02-01 8:35 UTC (permalink / raw) To: eric.dumazet; +Cc: davem, netdev, xiaoclu TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp to fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listener on both sides to accept connection from peer. md5 keys for peers are saved in listening socket. There are two cases in finding md5 key when connection is lost: 1.Passive receive RST: The message is send to well known port, tcp will associate it with listner. md5 key is gotten from listener. 2.Active receive RST (no sock): The message is send to ative side, there is no socket associated with the message. In this case, finding listener from source port, then find md5 key from listener. we are not loosing sercuriy here: packet is checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> --- v4: change title and change log. regerated after "tcp: md5: protects md5sig_info with RCU" net/ipv4/tcp_ipv4.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- net/ipv6/tcp_ipv6.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 567cca9..90e4793 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -593,6 +593,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; + const __u8 *hash_location = NULL; + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; #endif struct net *net; @@ -623,9 +627,36 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_md5_do_lookup(sk, - (union tcp_md5_addr *)&ip_hdr(skb)->saddr, - AF_INET) : NULL; + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, ip_hdr(skb)->daddr, + ntohs(th->source), inet_iif(skb)); + /* don't send rst if it can't find key */ + if (!sk1) + return; + rcu_read_lock(); + key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, AF_INET); + if (!key) + goto release_sk1; + + genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_md5_do_lookup(sk, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, + AF_INET) : NULL; + } + if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -653,6 +684,14 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) { + rcu_read_unlock(); + sock_put(sk1); + } +#endif } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c250181..d16414c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -923,6 +923,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); u32 seq = 0, ack_seq = 0; struct tcp_md5sig_key *key = NULL; +#ifdef CONFIG_TCP_MD5SIG + const __u8 *hash_location = NULL; + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; +#endif if (th->rst) return; @@ -931,8 +938,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) return; #ifdef CONFIG_TCP_MD5SIG - if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, &ipv6h->daddr, + ntohs(th->source), inet6_iif(skb)); + if (!sk1) + return; + + rcu_read_lock(); + key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); + if (!key) + goto release_sk1; + + genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; + } #endif if (th->ack) @@ -942,6 +973,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) (th->doff << 2); tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) { + rcu_read_unlock(); + sock_put(sk1); + } +#endif } static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] tcp: md5: RST: getting md5 key from listener 2012-02-01 8:35 ` [PATCH] tcp: md5: RST: getting md5 key from listener Shawn Lu @ 2012-02-01 9:54 ` Eric Dumazet 2012-02-01 17:44 ` David Miller 2012-02-01 18:48 ` Shawn Lu 0 siblings, 2 replies; 19+ messages in thread From: Eric Dumazet @ 2012-02-01 9:54 UTC (permalink / raw) To: Shawn Lu; +Cc: davem, netdev, xiaoclu Le mercredi 01 février 2012 à 00:35 -0800, Shawn Lu a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When > connection is gone, md5 key is lost, sending RST > without md5 hash is deem to ignored by peer. This can > be a problem since RST help protocal like bgp to fast > recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, > have listener on both sides to accept connection from peer. > md5 keys for peers are saved in listening socket. > > There are two cases in finding md5 key when connection is > lost: > 1.Passive receive RST: The message is send to well known port, > tcp will associate it with listner. md5 key is gotten from > listener. > > 2.Active receive RST (no sock): The message is send to ative > side, there is no socket associated with the message. In this > case, finding listener from source port, then find md5 key from > listener. > > we are not loosing sercuriy here: > packet is checked with md5 hash. No RST is generated > if md5 hash doesn't match or no md5 key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > v4: change title and change log. > regerated after "tcp: md5: protects md5sig_info with RCU" Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Thanks ! ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] tcp: md5: RST: getting md5 key from listener 2012-02-01 9:54 ` Eric Dumazet @ 2012-02-01 17:44 ` David Miller 2012-02-01 18:48 ` Shawn Lu 1 sibling, 0 replies; 19+ messages in thread From: David Miller @ 2012-02-01 17:44 UTC (permalink / raw) To: eric.dumazet; +Cc: shawn.lu, netdev, xiaoclu From: Eric Dumazet <eric.dumazet@gmail.com> Date: Wed, 01 Feb 2012 10:54:55 +0100 > Le mercredi 01 février 2012 à 00:35 -0800, Shawn Lu a écrit : >> TCP RST mechanism is broken in TCP md5(RFC2385). When >> connection is gone, md5 key is lost, sending RST >> without md5 hash is deem to ignored by peer. This can >> be a problem since RST help protocal like bgp to fast >> recove from peer crash. >> >> In most case, users of tcp md5, such as bgp and ldp, >> have listener on both sides to accept connection from peer. >> md5 keys for peers are saved in listening socket. >> >> There are two cases in finding md5 key when connection is >> lost: >> 1.Passive receive RST: The message is send to well known port, >> tcp will associate it with listner. md5 key is gotten from >> listener. >> >> 2.Active receive RST (no sock): The message is send to ative >> side, there is no socket associated with the message. In this >> case, finding listener from source port, then find md5 key from >> listener. >> >> we are not loosing sercuriy here: >> packet is checked with md5 hash. No RST is generated >> if md5 hash doesn't match or no md5 key can be found. >> >> Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> >> --- >> v4: change title and change log. >> regerated after "tcp: md5: protects md5sig_info with RCU" > > > Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Applied, thanks everyone. ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: RST: getting md5 key from listener 2012-02-01 9:54 ` Eric Dumazet 2012-02-01 17:44 ` David Miller @ 2012-02-01 18:48 ` Shawn Lu 1 sibling, 0 replies; 19+ messages in thread From: Shawn Lu @ 2012-02-01 18:48 UTC (permalink / raw) To: Eric Dumazet Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Hi,Eric With linux support for TCP AO not in picture right now. Are you interested in putting patch to enable md5 key change( RFC4808)? Or do you anybody else is working on linux implementation of TCP AO? I posted this question before and get no response yet. Thanks! Shawn -----Original Message----- From: Eric Dumazet [mailto:eric.dumazet@gmail.com] Sent: Wednesday, February 01, 2012 1:55 AM To: Shawn Lu Cc: davem@davemloft.net; netdev@vger.kernel.org; xiaoclu@gmail.com Subject: Re: [PATCH] tcp: md5: RST: getting md5 key from listener Le mercredi 01 février 2012 à 00:35 -0800, Shawn Lu a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When connection is > gone, md5 key is lost, sending RST without md5 hash is deem to ignored > by peer. This can be a problem since RST help protocal like bgp to > fast recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, have listener on > both sides to accept connection from peer. > md5 keys for peers are saved in listening socket. > > There are two cases in finding md5 key when connection is > lost: > 1.Passive receive RST: The message is send to well known port, tcp > will associate it with listner. md5 key is gotten from listener. > > 2.Active receive RST (no sock): The message is send to ative side, > there is no socket associated with the message. In this case, finding > listener from source port, then find md5 key from listener. > > we are not loosing sercuriy here: > packet is checked with md5 hash. No RST is generated if md5 hash > doesn't match or no md5 key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > v4: change title and change log. > regerated after "tcp: md5: protects md5sig_info with RCU" Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Thanks ! ^ permalink raw reply [flat|nested] 19+ messages in thread
* (unknown), @ 2012-02-01 0:50 Shawn Lu 2012-02-01 0:50 ` [PATCH] tcp: md5: fix md5 RST when both sides have listener Shawn Lu 0 siblings, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-02-01 0:50 UTC (permalink / raw) To: eric.dumazet; +Cc: davem, netdev, xiaoclu From: Shawn Lu <shawn.lu@ericsson.com> Subject: [PATCH] tcp: md5: fix md5 RST when both sides have listener In-Reply-To: RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-02-01 0:50 (unknown), Shawn Lu @ 2012-02-01 0:50 ` Shawn Lu 2012-02-01 4:08 ` Eric Dumazet 0 siblings, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-02-01 0:50 UTC (permalink / raw) To: eric.dumazet; +Cc: davem, netdev, xiaoclu TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp to fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listeners on both sides. md5 keys for peers are saved in listening socket. When passive side connection is gone, we can still get md5 key from listening socket. When active side of connection is gone, we can try to find listening socket through source port, and then md5 key. we are not loosing sercuriy here: packet is valified checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> --- net/ipv4/tcp_ipv4.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- net/ipv6/tcp_ipv6.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index da5d322..1a761c8 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -593,6 +593,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; + const __u8 *hash_location = NULL; + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; #endif struct net *net; @@ -623,9 +627,36 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_md5_do_lookup(sk, - (union tcp_md5_addr *)&ip_hdr(skb)->saddr, - AF_INET) : NULL; + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, ip_hdr(skb)->daddr, + ntohs(th->source), inet_iif(skb)); + /* don't send rst if it can't find key */ + if (!sk1) + return; + rcu_read_lock(); + key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, AF_INET); + if (!key) + goto release_sk1; + + genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_md5_do_lookup(sk, (union tcp_md5_addr *) + &ip_hdr(skb)->saddr, + AF_INET) : NULL; + } + if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -653,6 +684,14 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) { + rcu_read_unlock(); + sock_put(sk1); + } +#endif } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index bec41f9..3b139e2 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -925,6 +925,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); u32 seq = 0, ack_seq = 0; struct tcp_md5sig_key *key = NULL; +#ifdef CONFIG_TCP_MD5SIG + const __u8 *hash_location = NULL; + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; +#endif if (th->rst) return; @@ -933,8 +940,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) return; #ifdef CONFIG_TCP_MD5SIG - if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, &ipv6h->daddr, + ntohs(th->source), inet6_iif(skb)); + if (!sk1) + return; + + rcu_read_lock(); + key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); + if (!key) + goto release_sk1; + + genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; + } #endif if (th->ack) @@ -944,6 +975,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) (th->doff << 2); tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) { + rcu_read_unlock(); + sock_put(sk1); + } +#endif } static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-02-01 0:50 ` [PATCH] tcp: md5: fix md5 RST when both sides have listener Shawn Lu @ 2012-02-01 4:08 ` Eric Dumazet 0 siblings, 0 replies; 19+ messages in thread From: Eric Dumazet @ 2012-02-01 4:08 UTC (permalink / raw) To: Shawn Lu; +Cc: davem, netdev, xiaoclu Le mardi 31 janvier 2012 à 16:50 -0800, Shawn Lu a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When > connection is gone, md5 key is lost, sending RST > without md5 hash is deem to ignored by peer. This can > be a problem since RST help protocal like bgp to fast > recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, > have listeners on both sides. md5 keys for peers are > saved in listening socket. When passive side connection > is gone, we can still get md5 key from listening socket. > When active side of connection is gone, we can try to > find listening socket through source port, and then md5 > key. > we are not loosing sercuriy here: > packet is valified checked with md5 hash. No RST is generated > if md5 hash doesn't match or no md5 key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > net/ipv4/tcp_ipv4.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- > net/ipv6/tcp_ipv6.c | 43 +++++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 83 insertions(+), 5 deletions(-) > Hmm, ok but using RCU for the md5 lookup (instead of mere sock lock as done today) also means we need to protect struct tcp_md5sig_info itself I send a patch for this in a separate patch first, then David can apply your patch when I add my "Signed-off-by: ..." ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH] tcp: md5: fix md5 RST when both sides have listener @ 2012-01-31 2:07 Shawn Lu 2012-01-31 2:16 ` Eric Dumazet 0 siblings, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-01-31 2:07 UTC (permalink / raw) To: davem; +Cc: netdev, xiaoclu TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listeners on both sides. md5 keys for peers are saved in listening socket. When passive side connection is gone, we can still get md5 key from listening socket. When active side of connection is gone, we can try to find listening socket through source port, and then md5 key. we are not loosing sercuriy here: packet is valified checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> --- net/ipv4/tcp_ipv4.c | 31 ++++++++++++++++++++++++++++++- net/ipv6/tcp_ipv6.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 337ba4c..b2358b4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -601,6 +601,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; + __u8 *hash_location = NULL; + unsigned char newhash[16]; + int genhash; #endif struct net *net; @@ -631,7 +634,33 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, ip_hdr(skb)->daddr, + ntohs(th->source), inet_iif(skb)); + /* don't send rst if it can't find key */ + if (!sk) + return; + key = tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr); + if (!key) + return; + genhash = tcp_v4_md5_hash_skb(newhash, key, + NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + return; + + } else { + key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; + } + if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05a..1da99fd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1074,6 +1074,12 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); u32 seq = 0, ack_seq = 0; struct tcp_md5sig_key *key = NULL; +#ifdef CONFIG_TCP_MD5SIG + __u8 *hash_location = NULL; + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + unsigned char newhash[16]; + int genhash; +#endif if (th->rst) return; @@ -1082,8 +1088,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) return; #ifdef CONFIG_TCP_MD5SIG - if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, &ipv6h->daddr, + ntohs(th->source), inet6_iif(skb)); + if (!sk) + return; + + key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr); + if (!key) + return; + + genhash = tcp_v6_md5_hash_skb(newhash, key, + NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + return; + } else { + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; + } #endif if (th->ack) -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 2:07 Shawn Lu @ 2012-01-31 2:16 ` Eric Dumazet 2012-01-31 2:37 ` Shawn Lu 2012-01-31 8:39 ` Shawn Lu 0 siblings, 2 replies; 19+ messages in thread From: Eric Dumazet @ 2012-01-31 2:16 UTC (permalink / raw) To: Shawn Lu; +Cc: davem, netdev, xiaoclu Le 31 janvier 2012 03:07, Shawn Lu <shawn.lu@ericsson.com> a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When > connection is gone, md5 key is lost, sending RST without > md5 hash is deem to ignored by peer. This can be a problem > since RST help protocal like bgp fast recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, have listeners > on both sides. md5 keys for peers are saved in listening socket. > When passive side connection is gone, we can still get md5 key > from listening socket. When active side of connection is gone, > we can try to find listening socket through source port, and > then md5 key. > we are not loosing sercuriy here: packet is valified checked with > md5 hash. No RST is generated if md5 hash doesn't match or no md5 > key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > net/ipv4/tcp_ipv4.c | 31 ++++++++++++++++++++++++++++++- > net/ipv6/tcp_ipv6.c | 34 ++++++++++++++++++++++++++++++++-- > 2 files changed, 62 insertions(+), 3 deletions(-) > > diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c > index 337ba4c..b2358b4 100644 > --- a/net/ipv4/tcp_ipv4.c > +++ b/net/ipv4/tcp_ipv4.c > @@ -601,6 +601,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) > struct ip_reply_arg arg; > #ifdef CONFIG_TCP_MD5SIG > struct tcp_md5sig_key *key; > + __u8 *hash_location = NULL; > + unsigned char newhash[16]; > + int genhash; > #endif > struct net *net; > > @@ -631,7 +634,33 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) > arg.iov[0].iov_len = sizeof(rep.th); > > #ifdef CONFIG_TCP_MD5SIG > - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, ip_hdr(skb)->daddr, > + ntohs(th->source), inet_iif(skb)); > + /* don't send rst if it can't find key */ > + if (!sk) > + return; Now you have a socket in sk, you also are responsible to release the refcount taken in __inet_lookup_listener() > + key = tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr); > + if (!key) > + return; leak refcount > + genhash = tcp_v4_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != 0) > + return; same leak > + > + } else { > + key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; > + } > + > if (key) { > rep.opt[0] = htonl((TCPOPT_NOP << 24) | > (TCPOPT_NOP << 16) | > diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c > index 3edd05a..1da99fd 100644 > --- a/net/ipv6/tcp_ipv6.c > +++ b/net/ipv6/tcp_ipv6.c > @@ -1074,6 +1074,12 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) > const struct tcphdr *th = tcp_hdr(skb); > u32 seq = 0, ack_seq = 0; > struct tcp_md5sig_key *key = NULL; > +#ifdef CONFIG_TCP_MD5SIG > + __u8 *hash_location = NULL; > + struct ipv6hdr *ipv6h = ipv6_hdr(skb); > + unsigned char newhash[16]; > + int genhash; > +#endif > > if (th->rst) > return; > @@ -1082,8 +1088,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) > return; > > #ifdef CONFIG_TCP_MD5SIG > - if (sk) > - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, &ipv6h->daddr, > + ntohs(th->source), inet6_iif(skb)); > + if (!sk) > + return; > + > + key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr); > + if (!key) > + return; same leak > + > + genhash = tcp_v6_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != 0) > + return; same leak > + } else { > + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; > + } > #endif > > if (th->ack) > -- > 1.7.0.4 > > -- > To unsubscribe from this list: send the line "unsubscribe netdev" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 2:16 ` Eric Dumazet @ 2012-01-31 2:37 ` Shawn Lu 2012-01-31 8:39 ` Shawn Lu 1 sibling, 0 replies; 19+ messages in thread From: Shawn Lu @ 2012-01-31 2:37 UTC (permalink / raw) To: Eric Dumazet Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Yes. Eric is right. I will have to fix refcount problem. Will send out another patch later on. -----Original Message----- From: Eric Dumazet [mailto:eric.dumazet@gmail.com] Sent: Monday, January 30, 2012 6:16 PM To: Shawn Lu Cc: davem@davemloft.net; netdev@vger.kernel.org; xiaoclu@gmail.com Subject: Re: [PATCH] tcp: md5: fix md5 RST when both sides have listener Le 31 janvier 2012 03:07, Shawn Lu <shawn.lu@ericsson.com> a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When connection is > gone, md5 key is lost, sending RST without > md5 hash is deem to ignored by peer. This can be a problem since RST > help protocal like bgp fast recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, have listeners on > both sides. md5 keys for peers are saved in listening socket. > When passive side connection is gone, we can still get md5 key from > listening socket. When active side of connection is gone, we can try > to find listening socket through source port, and then md5 key. > we are not loosing sercuriy here: packet is valified checked with > md5 hash. No RST is generated if md5 hash doesn't match or no md5 key > can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > net/ipv4/tcp_ipv4.c | 31 ++++++++++++++++++++++++++++++- > net/ipv6/tcp_ipv6.c | 34 ++++++++++++++++++++++++++++++++-- > 2 files changed, 62 insertions(+), 3 deletions(-) > > diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index > 337ba4c..b2358b4 100644 > --- a/net/ipv4/tcp_ipv4.c > +++ b/net/ipv4/tcp_ipv4.c > @@ -601,6 +601,9 @@ static void tcp_v4_send_reset(struct sock *sk, > struct sk_buff *skb) > struct ip_reply_arg arg; > #ifdef CONFIG_TCP_MD5SIG > struct tcp_md5sig_key *key; > + __u8 *hash_location = NULL; > + unsigned char newhash[16]; > + int genhash; > #endif > struct net *net; > > @@ -631,7 +634,33 @@ static void tcp_v4_send_reset(struct sock *sk, > struct sk_buff *skb) > arg.iov[0].iov_len = sizeof(rep.th); > > #ifdef CONFIG_TCP_MD5SIG > - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : > NULL; > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket > + through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with > + finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk = > + __inet_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, > + ip_hdr(skb)->daddr, > + ntohs(th->source), > + inet_iif(skb)); > + /* don't send rst if it can't find key */ > + if (!sk) > + return; Now you have a socket in sk, you also are responsible to release the refcount taken in __inet_lookup_listener() > + key = tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr); > + if (!key) > + return; leak refcount > + genhash = tcp_v4_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != > + 0) > + return; same leak > + > + } else { > + key = sk ? tcp_v4_md5_do_lookup(sk, > + ip_hdr(skb)->saddr) : NULL; > + } > + > if (key) { > rep.opt[0] = htonl((TCPOPT_NOP << 24) | > (TCPOPT_NOP << 16) | diff --git > a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05a..1da99fd > 100644 > --- a/net/ipv6/tcp_ipv6.c > +++ b/net/ipv6/tcp_ipv6.c > @@ -1074,6 +1074,12 @@ static void tcp_v6_send_reset(struct sock *sk, > struct sk_buff *skb) > const struct tcphdr *th = tcp_hdr(skb); > u32 seq = 0, ack_seq = 0; > struct tcp_md5sig_key *key = NULL; > +#ifdef CONFIG_TCP_MD5SIG > + __u8 *hash_location = NULL; > + struct ipv6hdr *ipv6h = ipv6_hdr(skb); > + unsigned char newhash[16]; > + int genhash; > +#endif > > if (th->rst) > return; > @@ -1082,8 +1088,32 @@ static void tcp_v6_send_reset(struct sock *sk, > struct sk_buff *skb) > return; > > #ifdef CONFIG_TCP_MD5SIG > - if (sk) > - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket > + through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with > + finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, > + &ipv6h->daddr, > + ntohs(th->source), > + inet6_iif(skb)); > + if (!sk) > + return; > + > + key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr); > + if (!key) > + return; same leak > + > + genhash = tcp_v6_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != > + 0) > + return; same leak > + } else { > + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : > + NULL; > + } > #endif > > if (th->ack) > -- > 1.7.0.4 > > -- > To unsubscribe from this list: send the line "unsubscribe netdev" in > the body of a message to majordomo@vger.kernel.org More majordomo info > at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 2:16 ` Eric Dumazet 2012-01-31 2:37 ` Shawn Lu @ 2012-01-31 8:39 ` Shawn Lu 2012-01-31 9:05 ` Eric Dumazet 1 sibling, 1 reply; 19+ messages in thread From: Shawn Lu @ 2012-01-31 8:39 UTC (permalink / raw) To: Eric Dumazet Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Resubmit after fixing the sk refcount leak problem pointed out by Eric. TCP RST mechanism is broken in TCP md5(RFC2385).When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listeners on both sides. md5 keys for peers are saved in listening socket. When passive side connection is gone, we can still get md5 key from listening socket. When active side of connection is gone, we can try to find listening socket through source port, and then md5 key. we are not loosing sercuriy here: packet is valified checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> --- net/ipv4/tcp_ipv4.c | 38 +++++++++++++++++++++++++++++++++++++- net/ipv6/tcp_ipv6.c | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 337ba4c..6ed1c4a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -601,6 +601,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) struct ip_reply_arg arg; #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; + __u8 *hash_location = NULL; + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; #endif struct net *net; @@ -631,7 +635,33 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, ip_hdr(skb)->daddr, + ntohs(th->source), inet_iif(skb)); + /* don't send rst if it can't find key */ + if (!sk1) + return; + key = tcp_v4_md5_do_lookup(sk1, ip_hdr(skb)->saddr); + if (!key) + goto release_sk1; + genhash = tcp_v4_md5_hash_skb(newhash, key, + NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + + } else { + key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; + } + if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | @@ -659,6 +689,12 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) + sock_put(sk1); +#endif } /* The code following below sending ACKs in SYN-RECV and TIME-WAIT states diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05a..32507e8 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1074,6 +1074,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) const struct tcphdr *th = tcp_hdr(skb); u32 seq = 0, ack_seq = 0; struct tcp_md5sig_key *key = NULL; +#ifdef CONFIG_TCP_MD5SIG + __u8 *hash_location = NULL; + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + unsigned char newhash[16]; + int genhash; + struct sock *sk1 = NULL; +#endif if (th->rst) return; @@ -1082,8 +1089,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) return; #ifdef CONFIG_TCP_MD5SIG - if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); + hash_location = tcp_parse_md5sig_option(th); + if (!sk && hash_location) { + /* + * active side is lost. Try to find listening socket through + * source port, and then find md5 key through listening socket. + * we are not loose security here: + * Incoming packet is checked with md5 hash with finding key, + * no RST generated if md5 hash doesn't match. + */ + sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), + &tcp_hashinfo, &ipv6h->daddr, + ntohs(th->source), inet6_iif(skb)); + if (!sk1) + return; + + key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); + if (!key) + goto release_sk1; + + genhash = tcp_v6_md5_hash_skb(newhash, key, + NULL, NULL, skb); + if (genhash || memcmp(hash_location, newhash, 16) != 0) + goto release_sk1; + } else { + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL; + } #endif if (th->ack) @@ -1093,6 +1124,12 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) (th->doff << 2); tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0); + +#ifdef CONFIG_TCP_MD5SIG +release_sk1: + if (sk1) + sock_put(sk1); +#endif } static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, -- 1.7.0.4 -----Original Message----- From: Eric Dumazet [mailto:eric.dumazet@gmail.com] Sent: Monday, January 30, 2012 6:16 PM To: Shawn Lu Cc: davem@davemloft.net; netdev@vger.kernel.org; xiaoclu@gmail.com Subject: Re: [PATCH] tcp: md5: fix md5 RST when both sides have listener Le 31 janvier 2012 03:07, Shawn Lu <shawn.lu@ericsson.com> a écrit : > TCP RST mechanism is broken in TCP md5(RFC2385). When connection is > gone, md5 key is lost, sending RST without > md5 hash is deem to ignored by peer. This can be a problem since RST > help protocal like bgp fast recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, have listeners on > both sides. md5 keys for peers are saved in listening socket. > When passive side connection is gone, we can still get md5 key from > listening socket. When active side of connection is gone, we can try > to find listening socket through source port, and then md5 key. > we are not loosing sercuriy here: packet is valified checked with > md5 hash. No RST is generated if md5 hash doesn't match or no md5 key > can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > net/ipv4/tcp_ipv4.c | 31 ++++++++++++++++++++++++++++++- > net/ipv6/tcp_ipv6.c | 34 ++++++++++++++++++++++++++++++++-- > 2 files changed, 62 insertions(+), 3 deletions(-) > > diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index > 337ba4c..b2358b4 100644 > --- a/net/ipv4/tcp_ipv4.c > +++ b/net/ipv4/tcp_ipv4.c > @@ -601,6 +601,9 @@ static void tcp_v4_send_reset(struct sock *sk, > struct sk_buff *skb) > struct ip_reply_arg arg; > #ifdef CONFIG_TCP_MD5SIG > struct tcp_md5sig_key *key; > + __u8 *hash_location = NULL; > + unsigned char newhash[16]; > + int genhash; > #endif > struct net *net; > > @@ -631,7 +634,33 @@ static void tcp_v4_send_reset(struct sock *sk, > struct sk_buff *skb) > arg.iov[0].iov_len = sizeof(rep.th); > > #ifdef CONFIG_TCP_MD5SIG > - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : > NULL; > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket > + through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with > + finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk = > + __inet_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, > + ip_hdr(skb)->daddr, > + ntohs(th->source), > + inet_iif(skb)); > + /* don't send rst if it can't find key */ > + if (!sk) > + return; Now you have a socket in sk, you also are responsible to release the refcount taken in __inet_lookup_listener() > + key = tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr); > + if (!key) > + return; leak refcount > + genhash = tcp_v4_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != > + 0) > + return; same leak > + > + } else { > + key = sk ? tcp_v4_md5_do_lookup(sk, > + ip_hdr(skb)->saddr) : NULL; > + } > + > if (key) { > rep.opt[0] = htonl((TCPOPT_NOP << 24) | > (TCPOPT_NOP << 16) | diff --git > a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3edd05a..1da99fd > 100644 > --- a/net/ipv6/tcp_ipv6.c > +++ b/net/ipv6/tcp_ipv6.c > @@ -1074,6 +1074,12 @@ static void tcp_v6_send_reset(struct sock *sk, > struct sk_buff *skb) > const struct tcphdr *th = tcp_hdr(skb); > u32 seq = 0, ack_seq = 0; > struct tcp_md5sig_key *key = NULL; > +#ifdef CONFIG_TCP_MD5SIG > + __u8 *hash_location = NULL; > + struct ipv6hdr *ipv6h = ipv6_hdr(skb); > + unsigned char newhash[16]; > + int genhash; > +#endif > > if (th->rst) > return; > @@ -1082,8 +1088,32 @@ static void tcp_v6_send_reset(struct sock *sk, > struct sk_buff *skb) > return; > > #ifdef CONFIG_TCP_MD5SIG > - if (sk) > - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket > + through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with > + finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, > + &ipv6h->daddr, > + ntohs(th->source), > + inet6_iif(skb)); > + if (!sk) > + return; > + > + key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr); > + if (!key) > + return; same leak > + > + genhash = tcp_v6_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != > + 0) > + return; same leak > + } else { > + key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : > + NULL; > + } > #endif > > if (th->ack) > -- > 1.7.0.4 > > -- > To unsubscribe from this list: send the line "unsubscribe netdev" in > the body of a message to majordomo@vger.kernel.org More majordomo info > at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 8:39 ` Shawn Lu @ 2012-01-31 9:05 ` Eric Dumazet 2012-01-31 13:33 ` Eric Dumazet 0 siblings, 1 reply; 19+ messages in thread From: Eric Dumazet @ 2012-01-31 9:05 UTC (permalink / raw) To: Shawn Lu; +Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Le mardi 31 janvier 2012 à 03:39 -0500, Shawn Lu a écrit : > Resubmit after fixing the sk refcount leak problem pointed out by Eric. > > > TCP RST mechanism is broken in TCP md5(RFC2385).When > connection is gone, md5 key is lost, sending RST without > md5 hash is deem to ignored by peer. This can be a problem > since RST help protocal like bgp fast recove from peer crash. > > In most case, users of tcp md5, such as bgp and ldp, have > listeners on both sides. md5 keys for peers are saved in > listening socket. When passive side connection is gone, > we can still get md5 key from listening socket. When active > side of connection is gone, we can try to find listening socket > through source port, and then md5 key. > we are not loosing sercuriy here: packet is valified checked with > md5 hash. No RST is generated if md5 hash doesn't match or no md5 > key can be found. > > Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> > --- > net/ipv4/tcp_ipv4.c | 38 +++++++++++++++++++++++++++++++++++++- > net/ipv6/tcp_ipv6.c | 41 +++++++++++++++++++++++++++++++++++++++-- > 2 files changed, 76 insertions(+), 3 deletions(-) > > diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 337ba4c..6ed1c4a 100644 > --- a/net/ipv4/tcp_ipv4.c > +++ b/net/ipv4/tcp_ipv4.c > @@ -601,6 +601,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) > struct ip_reply_arg arg; > #ifdef CONFIG_TCP_MD5SIG > struct tcp_md5sig_key *key; > + __u8 *hash_location = NULL; > + unsigned char newhash[16]; > + int genhash; > + struct sock *sk1 = NULL; > #endif > struct net *net; > > @@ -631,7 +635,33 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) > arg.iov[0].iov_len = sizeof(rep.th); > > #ifdef CONFIG_TCP_MD5SIG > - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; > + hash_location = tcp_parse_md5sig_option(th); > + if (!sk && hash_location) { > + /* > + * active side is lost. Try to find listening socket through > + * source port, and then find md5 key through listening socket. > + * we are not loose security here: > + * Incoming packet is checked with md5 hash with finding key, > + * no RST generated if md5 hash doesn't match. > + */ > + sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev), > + &tcp_hashinfo, ip_hdr(skb)->daddr, > + ntohs(th->source), inet_iif(skb)); > + /* don't send rst if it can't find key */ > + if (!sk1) > + return; > + key = tcp_v4_md5_do_lookup(sk1, ip_hdr(skb)->saddr); Hmm... The second problem is that its not safe to call tcp_v4_md5_do_lookup() on an unlocked socket. And locking a listener is way too expensive, since a listener socket is already a contention point. An attacker could send forged tcp md5 packets to slow down a server. A proper patch needs RCU conversion first. > + if (!key) > + goto release_sk1; > + genhash = tcp_v4_md5_hash_skb(newhash, key, > + NULL, NULL, skb); > + if (genhash || memcmp(hash_location, newhash, 16) != 0) > + goto release_sk1; > + > + } else { > + key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; > + } > + > if (key) { > rep.opt[0] = htonl((TCPOPT_NOP << 24) | > (TCPOPT_NOP << 16) | > @@ -659,6 +689,12 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) > > TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); > TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); > + > +#ifdef CONFIG_TCP_MD5SIG > +release_sk1: > + if (sk1) > + sock_put(sk1); > +#endif > } ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 9:05 ` Eric Dumazet @ 2012-01-31 13:33 ` Eric Dumazet 2012-01-31 18:15 ` Shawn Lu 0 siblings, 1 reply; 19+ messages in thread From: Eric Dumazet @ 2012-01-31 13:33 UTC (permalink / raw) To: Shawn Lu; +Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Le mardi 31 janvier 2012 à 10:05 +0100, Eric Dumazet a écrit : > Hmm... The second problem is that its not safe to call > tcp_v4_md5_do_lookup() on an unlocked socket. > > And locking a listener is way too expensive, since a listener socket is > already a contention point. > > An attacker could send forged tcp md5 packets to slow down a server. > > A proper patch needs RCU conversion first. I am working on this RCU conversion and big md5 cleanup, using a single list of keys. You can then add your fix on top of this work. union tcp_md5_addr { struct in_addr a4; #if IS_ENABLED(CONFIG_IPV6) struct in6_addr a6; #endif }; /* - key database */ struct tcp_md5sig_key { struct hlist_node node; u8 keylen; u8 family; /* AF_INET or AF_INET6 */ union tcp_md5_addr addr; u8 key[TCP_MD5SIG_MAXKEYLEN]; struct rcu_head rcu; }; /* - sock block */ struct tcp_md5sig_info { struct hlist_head head; }; ^ permalink raw reply [flat|nested] 19+ messages in thread
* RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener 2012-01-31 13:33 ` Eric Dumazet @ 2012-01-31 18:15 ` Shawn Lu 0 siblings, 0 replies; 19+ messages in thread From: Shawn Lu @ 2012-01-31 18:15 UTC (permalink / raw) To: Eric Dumazet Cc: davem@davemloft.net, netdev@vger.kernel.org, xiaoclu@gmail.com Thanks! Eric. Good catch. Will using RCU to pretect the md5 key. -----Original Message----- From: Eric Dumazet [mailto:eric.dumazet@gmail.com] Sent: Tuesday, January 31, 2012 5:34 AM To: Shawn Lu Cc: davem@davemloft.net; netdev@vger.kernel.org; xiaoclu@gmail.com Subject: RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener Le mardi 31 janvier 2012 à 10:05 +0100, Eric Dumazet a écrit : > Hmm... The second problem is that its not safe to call > tcp_v4_md5_do_lookup() on an unlocked socket. > > And locking a listener is way too expensive, since a listener socket > is already a contention point. > > An attacker could send forged tcp md5 packets to slow down a server. > > A proper patch needs RCU conversion first. I am working on this RCU conversion and big md5 cleanup, using a single list of keys. You can then add your fix on top of this work. [shawnlu] Good idea. I will resumit using rcu. union tcp_md5_addr { struct in_addr a4; #if IS_ENABLED(CONFIG_IPV6) struct in6_addr a6; #endif }; /* - key database */ struct tcp_md5sig_key { struct hlist_node node; u8 keylen; u8 family; /* AF_INET or AF_INET6 */ union tcp_md5_addr addr; u8 key[TCP_MD5SIG_MAXKEYLEN]; struct rcu_head rcu; }; /* - sock block */ struct tcp_md5sig_info { struct hlist_head head; }; ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2012-02-01 18:48 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <RE: [PATCH] tcp: md5: fix md5 RST when both sides have listener> 2012-01-31 23:53 ` [PATCH] tcp: md5: fix md5 RST when both sides have listener Shawn Lu 2012-02-01 5:09 ` Eric Dumazet 2012-02-01 7:48 ` Shawn Lu 2012-02-01 7:53 ` Eric Dumazet 2012-02-01 8:11 ` Shawn Lu 2012-02-01 9:25 ` Eric Dumazet 2012-02-01 8:35 ` [PATCH] tcp: md5: RST: getting md5 key from listener Shawn Lu 2012-02-01 9:54 ` Eric Dumazet 2012-02-01 17:44 ` David Miller 2012-02-01 18:48 ` Shawn Lu 2012-02-01 0:50 (unknown), Shawn Lu 2012-02-01 0:50 ` [PATCH] tcp: md5: fix md5 RST when both sides have listener Shawn Lu 2012-02-01 4:08 ` Eric Dumazet -- strict thread matches above, loose matches on Subject: below -- 2012-01-31 2:07 Shawn Lu 2012-01-31 2:16 ` Eric Dumazet 2012-01-31 2:37 ` Shawn Lu 2012-01-31 8:39 ` Shawn Lu 2012-01-31 9:05 ` Eric Dumazet 2012-01-31 13:33 ` Eric Dumazet 2012-01-31 18:15 ` Shawn Lu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).