Commit 1ad98e9d authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

tcp/dccp: fix lockdep issue when SYN is backlogged

In normal SYN processing, packets are handled without listener
lock and in RCU protected ingress path.

But syzkaller is known to be able to trick us and SYN
packets might be processed in process context, after being
queued into socket backlog.

In commit 06f877d6 ("tcp/dccp: fix other lockdep splats
accessing ireq_opt") I made a very stupid fix, that happened
to work mostly because of the regular path being RCU protected.

Really the thing protecting ireq->ireq_opt is RCU read lock,
and the pseudo request refcnt is not relevant.

This patch extends what I did in commit 449809a6 ("tcp/dccp:
block BH for SYN processing") by adding an extra rcu_read_{lock|unlock}
pair in the paths that might be taken when processing SYN from
socket backlog (thus possibly in process context)

Fixes: 06f877d6 ("tcp/dccp: fix other lockdep splats accessing ireq_opt")
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarsyzbot <syzkaller@googlegroups.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c8424ddd
...@@ -132,8 +132,7 @@ static inline int inet_request_bound_dev_if(const struct sock *sk, ...@@ -132,8 +132,7 @@ static inline int inet_request_bound_dev_if(const struct sock *sk,
static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq) static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq)
{ {
return rcu_dereference_check(ireq->ireq_opt, return rcu_dereference(ireq->ireq_opt);
refcount_read(&ireq->req.rsk_refcnt) > 0);
} }
struct inet_cork { struct inet_cork {
......
...@@ -606,11 +606,13 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, ...@@ -606,11 +606,13 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (sk->sk_state == DCCP_LISTEN) { if (sk->sk_state == DCCP_LISTEN) {
if (dh->dccph_type == DCCP_PKT_REQUEST) { if (dh->dccph_type == DCCP_PKT_REQUEST) {
/* It is possible that we process SYN packets from backlog, /* It is possible that we process SYN packets from backlog,
* so we need to make sure to disable BH right there. * so we need to make sure to disable BH and RCU right there.
*/ */
rcu_read_lock();
local_bh_disable(); local_bh_disable();
acceptable = inet_csk(sk)->icsk_af_ops->conn_request(sk, skb) >= 0; acceptable = inet_csk(sk)->icsk_af_ops->conn_request(sk, skb) >= 0;
local_bh_enable(); local_bh_enable();
rcu_read_unlock();
if (!acceptable) if (!acceptable)
return 1; return 1;
consume_skb(skb); consume_skb(skb);
......
...@@ -6009,11 +6009,13 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -6009,11 +6009,13 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)
if (th->fin) if (th->fin)
goto discard; goto discard;
/* It is possible that we process SYN packets from backlog, /* It is possible that we process SYN packets from backlog,
* so we need to make sure to disable BH right there. * so we need to make sure to disable BH and RCU right there.
*/ */
rcu_read_lock();
local_bh_disable(); local_bh_disable();
acceptable = icsk->icsk_af_ops->conn_request(sk, skb) >= 0; acceptable = icsk->icsk_af_ops->conn_request(sk, skb) >= 0;
local_bh_enable(); local_bh_enable();
rcu_read_unlock();
if (!acceptable) if (!acceptable)
return 1; return 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment