diff options
| author | Eric Dumazet <edumazet@google.com> | 2017-03-22 11:30:21 +0000 |
|---|---|---|
| committer | android-build-merger <android-build-merger@google.com> | 2017-03-22 11:30:21 +0000 |
| commit | f0a80cb8a7f23e8d1d1cf79480ee93d056a0580b (patch) | |
| tree | 9978b91575a9b4da284087c956254caab9947165 /net | |
| parent | 9cf061bb472f0c1c86143b769f5d8d3bdf5f3143 (diff) | |
| parent | d0ebde92fbeb98eedbfce15cef3c86b652846d25 (diff) | |
dccp: fix use-after-free in dccp_feat_activate_values
am: d0ebde92fb
Change-Id: I80863cbb814b1486069ee311e3f8543c7d34b74a
Diffstat (limited to 'net')
| -rw-r--r-- | net/dccp/minisocks.c | 24 |
1 files changed, 16 insertions, 8 deletions
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index e314caa39176..68eed344b471 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -146,6 +146,13 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, struct dccp_request_sock *dreq = dccp_rsk(req); bool own_req; + /* TCP/DCCP listeners became lockless. + * DCCP stores complex state in its request_sock, so we need + * a protection for them, now this code runs without being protected + * by the parent (listener) lock. + */ + spin_lock_bh(&dreq->dreq_lock); + /* Check for retransmitted REQUEST */ if (dccp_hdr(skb)->dccph_type == DCCP_PKT_REQUEST) { @@ -160,7 +167,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, inet_rtx_syn_ack(sk, req); } /* Network Duplicate, discard packet */ - return NULL; + goto out; } DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; @@ -186,20 +193,20 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, req, &own_req); - if (!child) - goto listen_overflow; - - return inet_csk_complete_hashdance(sk, child, req, own_req); + if (child) { + child = inet_csk_complete_hashdance(sk, child, req, own_req); + goto out; + } -listen_overflow: - dccp_pr_debug("listen_overflow!\n"); DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_TOO_BUSY; drop: if (dccp_hdr(skb)->dccph_type != DCCP_PKT_RESET) req->rsk_ops->send_reset(sk, skb); inet_csk_reqsk_queue_drop(sk, req); - return NULL; +out: + spin_unlock_bh(&dreq->dreq_lock); + return child; } EXPORT_SYMBOL_GPL(dccp_check_req); @@ -250,6 +257,7 @@ int dccp_reqsk_init(struct request_sock *req, { struct dccp_request_sock *dreq = dccp_rsk(req); + spin_lock_init(&dreq->dreq_lock); inet_rsk(req)->ir_rmt_port = dccp_hdr(skb)->dccph_sport; inet_rsk(req)->ir_num = ntohs(dccp_hdr(skb)->dccph_dport); inet_rsk(req)->acked = 0; |
