diff options
| -rw-r--r-- | net/rxrpc/input.c | 12 | ||||
| -rw-r--r-- | net/rxrpc/local_object.c | 3 |
2 files changed, 10 insertions, 5 deletions
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index 4c6f9d0a00e7..c2c35cf4e308 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c | |||
| @@ -1161,19 +1161,19 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb) | |||
| 1161 | * handle data received on the local endpoint | 1161 | * handle data received on the local endpoint |
| 1162 | * - may be called in interrupt context | 1162 | * - may be called in interrupt context |
| 1163 | * | 1163 | * |
| 1164 | * The socket is locked by the caller and this prevents the socket from being | 1164 | * [!] Note that as this is called from the encap_rcv hook, the socket is not |
| 1165 | * shut down and the local endpoint from going away, thus sk_user_data will not | 1165 | * held locked by the caller and nothing prevents sk_user_data on the UDP from |
| 1166 | * be cleared until this function returns. | 1166 | * being cleared in the middle of processing this function. |
| 1167 | * | 1167 | * |
| 1168 | * Called with the RCU read lock held from the IP layer via UDP. | 1168 | * Called with the RCU read lock held from the IP layer via UDP. |
| 1169 | */ | 1169 | */ |
| 1170 | int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb) | 1170 | int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb) |
| 1171 | { | 1171 | { |
| 1172 | struct rxrpc_local *local = rcu_dereference_sk_user_data(udp_sk); | ||
| 1172 | struct rxrpc_connection *conn; | 1173 | struct rxrpc_connection *conn; |
| 1173 | struct rxrpc_channel *chan; | 1174 | struct rxrpc_channel *chan; |
| 1174 | struct rxrpc_call *call = NULL; | 1175 | struct rxrpc_call *call = NULL; |
| 1175 | struct rxrpc_skb_priv *sp; | 1176 | struct rxrpc_skb_priv *sp; |
| 1176 | struct rxrpc_local *local = udp_sk->sk_user_data; | ||
| 1177 | struct rxrpc_peer *peer = NULL; | 1177 | struct rxrpc_peer *peer = NULL; |
| 1178 | struct rxrpc_sock *rx = NULL; | 1178 | struct rxrpc_sock *rx = NULL; |
| 1179 | unsigned int channel; | 1179 | unsigned int channel; |
| @@ -1181,6 +1181,10 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb) | |||
| 1181 | 1181 | ||
| 1182 | _enter("%p", udp_sk); | 1182 | _enter("%p", udp_sk); |
| 1183 | 1183 | ||
| 1184 | if (unlikely(!local)) { | ||
| 1185 | kfree_skb(skb); | ||
| 1186 | return 0; | ||
| 1187 | } | ||
| 1184 | if (skb->tstamp == 0) | 1188 | if (skb->tstamp == 0) |
| 1185 | skb->tstamp = ktime_get_real(); | 1189 | skb->tstamp = ktime_get_real(); |
| 1186 | 1190 | ||
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 15cf42d5b53a..01959db51445 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c | |||
| @@ -304,7 +304,8 @@ nomem: | |||
| 304 | ret = -ENOMEM; | 304 | ret = -ENOMEM; |
| 305 | sock_error: | 305 | sock_error: |
| 306 | mutex_unlock(&rxnet->local_mutex); | 306 | mutex_unlock(&rxnet->local_mutex); |
| 307 | kfree(local); | 307 | if (local) |
| 308 | call_rcu(&local->rcu, rxrpc_local_rcu); | ||
| 308 | _leave(" = %d", ret); | 309 | _leave(" = %d", ret); |
| 309 | return ERR_PTR(ret); | 310 | return ERR_PTR(ret); |
| 310 | 311 | ||
