| From 744841f0c36de60a08b50081b0ead00e115cf447 Mon Sep 17 00:00:00 2001 |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Mon, 14 Oct 2019 06:04:38 -0700 |
| Subject: [PATCH] rxrpc: use rcu protection while reading sk->sk_user_data |
| |
| commit 2ca4f6ca4562594ef161e4140c2a5e0e5282967b upstream. |
| |
| We need to extend the rcu_read_lock() section in rxrpc_error_report() |
| and use rcu_dereference_sk_user_data() instead of plain access |
| to sk->sk_user_data to make sure all rules are respected. |
| |
| The compiler wont reload sk->sk_user_data at will, and RCU rules |
| prevent memory beeing freed too soon. |
| |
| Fixes: f0308fb07080 ("rxrpc: Fix possible NULL pointer access in ICMP handling") |
| Fixes: 17926a79320a ("[AF_RXRPC]: Provide secure RxRPC sockets for use by userspace and kernel both") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Cc: David Howells <dhowells@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c |
| index 740b5d64e4dd..e92e0526e0dc 100644 |
| --- a/net/rxrpc/peer_event.c |
| +++ b/net/rxrpc/peer_event.c |
| @@ -147,13 +147,16 @@ void rxrpc_error_report(struct sock *sk) |
| { |
| struct sock_exterr_skb *serr; |
| struct sockaddr_rxrpc srx; |
| - struct rxrpc_local *local = sk->sk_user_data; |
| + struct rxrpc_local *local; |
| struct rxrpc_peer *peer; |
| struct sk_buff *skb; |
| |
| - if (unlikely(!local)) |
| + rcu_read_lock(); |
| + local = rcu_dereference_sk_user_data(sk); |
| + if (unlikely(!local)) { |
| + rcu_read_unlock(); |
| return; |
| - |
| + } |
| _enter("%p{%d}", sk, local->debug_id); |
| |
| /* Clear the outstanding error value on the socket so that it doesn't |
| @@ -163,6 +166,7 @@ void rxrpc_error_report(struct sock *sk) |
| |
| skb = sock_dequeue_err_skb(sk); |
| if (!skb) { |
| + rcu_read_unlock(); |
| _leave("UDP socket errqueue empty"); |
| return; |
| } |
| @@ -170,11 +174,11 @@ void rxrpc_error_report(struct sock *sk) |
| serr = SKB_EXT_ERR(skb); |
| if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { |
| _leave("UDP empty message"); |
| + rcu_read_unlock(); |
| rxrpc_free_skb(skb, rxrpc_skb_rx_freed); |
| return; |
| } |
| |
| - rcu_read_lock(); |
| peer = rxrpc_lookup_peer_icmp_rcu(local, skb, &srx); |
| if (peer && !rxrpc_get_peer_maybe(peer)) |
| peer = NULL; |
| -- |
| 2.7.4 |
| |