diff options
| author | Eric Dumazet <edumazet@google.com> | 2016-07-08 05:03:57 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2016-07-09 18:14:17 -0400 |
| commit | 95556a883834122c616bbeb942654d745ceb9712 (patch) | |
| tree | 38d19b84c9d1d2b632f0c08a321dd9fb44c7e5f3 /net/dccp | |
| parent | 03addc2bcebd953e74c52f0664629032fd9767e9 (diff) | |
dccp: avoid deadlock in dccp_v4_ctl_send_reset
In the prep work I did before enabling BH while handling socket backlog,
I missed two points in DCCP :
1) dccp_v4_ctl_send_reset() uses bh_lock_sock(), assuming BH were
blocked. It is not anymore always true.
2) dccp_v4_route_skb() was using __IP_INC_STATS() instead of
IP_INC_STATS()
A similar fix was done for TCP, in commit 47dcc20a39d0
("ipv4: tcp: ip_send_unicast_reply() is not BH safe")
Fixes: 7309f8821fd6 ("dccp: do not assume DCCP code is non preemptible")
Fixes: 5413d1babe8f ("net: do not block BH while processing socket backlog")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp')
| -rw-r--r-- | net/dccp/ipv4.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 5c7e413a3ae4..25dd25b47d41 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
| @@ -462,7 +462,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, | |||
| 462 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); | 462 | security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
| 463 | rt = ip_route_output_flow(net, &fl4, sk); | 463 | rt = ip_route_output_flow(net, &fl4, sk); |
| 464 | if (IS_ERR(rt)) { | 464 | if (IS_ERR(rt)) { |
| 465 | __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); | 465 | IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
| 466 | return NULL; | 466 | return NULL; |
| 467 | } | 467 | } |
| 468 | 468 | ||
| @@ -527,17 +527,19 @@ static void dccp_v4_ctl_send_reset(const struct sock *sk, struct sk_buff *rxskb) | |||
| 527 | rxiph->daddr); | 527 | rxiph->daddr); |
| 528 | skb_dst_set(skb, dst_clone(dst)); | 528 | skb_dst_set(skb, dst_clone(dst)); |
| 529 | 529 | ||
| 530 | local_bh_disable(); | ||
| 530 | bh_lock_sock(ctl_sk); | 531 | bh_lock_sock(ctl_sk); |
| 531 | err = ip_build_and_send_pkt(skb, ctl_sk, | 532 | err = ip_build_and_send_pkt(skb, ctl_sk, |
| 532 | rxiph->daddr, rxiph->saddr, NULL); | 533 | rxiph->daddr, rxiph->saddr, NULL); |
| 533 | bh_unlock_sock(ctl_sk); | 534 | bh_unlock_sock(ctl_sk); |
| 534 | 535 | ||
| 535 | if (net_xmit_eval(err) == 0) { | 536 | if (net_xmit_eval(err) == 0) { |
| 536 | DCCP_INC_STATS(DCCP_MIB_OUTSEGS); | 537 | __DCCP_INC_STATS(DCCP_MIB_OUTSEGS); |
| 537 | DCCP_INC_STATS(DCCP_MIB_OUTRSTS); | 538 | __DCCP_INC_STATS(DCCP_MIB_OUTRSTS); |
| 538 | } | 539 | } |
| 540 | local_bh_enable(); | ||
| 539 | out: | 541 | out: |
| 540 | dst_release(dst); | 542 | dst_release(dst); |
| 541 | } | 543 | } |
| 542 | 544 | ||
| 543 | static void dccp_v4_reqsk_destructor(struct request_sock *req) | 545 | static void dccp_v4_reqsk_destructor(struct request_sock *req) |
