Message ID | 158099730157.2198513.14087711871251670411.stgit@warthog.procyon.org.uk |
---|---|
State | Accepted |
Delegated to: | David Miller |
Headers | show |
Series | [net] rxrpc: Fix service call disconnection | expand |
From: David Howells <dhowells@redhat.com> Date: Thu, 06 Feb 2020 13:55:01 +0000 > The recent patch that substituted a flag on an rxrpc_call for the > connection pointer being NULL as an indication that a call was disconnected > puts the set_bit in the wrong place for service calls. This is only a > problem if a call is implicitly terminated by a new call coming in on the > same connection channel instead of a terminating ACK packet. > > In such a case, rxrpc_input_implicit_end_call() calls > __rxrpc_disconnect_call(), which is now (incorrectly) setting the > disconnection bit, meaning that when rxrpc_release_call() is later called, > it doesn't call rxrpc_disconnect_call() and so the call isn't removed from > the peer's error distribution list and the list gets corrupted. > > KASAN finds the issue as an access after release on a call, but the > position at which it occurs is confusing as it appears to be related to a > different call (the call site is where the latter call is being removed > from the error distribution list and either the next or pprev pointer > points to a previously released call). > > Fix this by moving the setting of the flag from __rxrpc_disconnect_call() > to rxrpc_disconnect_call() in the same place that the connection pointer > was being cleared. > > Fixes: 5273a191dca6 ("rxrpc: Fix NULL pointer deref due to call->conn being cleared on disconnect") > Signed-off-by: David Howells <dhowells@redhat.com> Applied and queued up for -stable.
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index c0b3154f7a7e..19e141eeed17 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -171,8 +171,6 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn, _enter("%d,%x", conn->debug_id, call->cid); - set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); - if (rcu_access_pointer(chan->call) == call) { /* Save the result of the call so that we can repeat it if necessary * through the channel, whilst disposing of the actual call record. @@ -225,6 +223,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call) __rxrpc_disconnect_call(conn, call); spin_unlock(&conn->channel_lock); + set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); conn->idle_timestamp = jiffies; }
The recent patch that substituted a flag on an rxrpc_call for the connection pointer being NULL as an indication that a call was disconnected puts the set_bit in the wrong place for service calls. This is only a problem if a call is implicitly terminated by a new call coming in on the same connection channel instead of a terminating ACK packet. In such a case, rxrpc_input_implicit_end_call() calls __rxrpc_disconnect_call(), which is now (incorrectly) setting the disconnection bit, meaning that when rxrpc_release_call() is later called, it doesn't call rxrpc_disconnect_call() and so the call isn't removed from the peer's error distribution list and the list gets corrupted. KASAN finds the issue as an access after release on a call, but the position at which it occurs is confusing as it appears to be related to a different call (the call site is where the latter call is being removed from the error distribution list and either the next or pprev pointer points to a previously released call). Fix this by moving the setting of the flag from __rxrpc_disconnect_call() to rxrpc_disconnect_call() in the same place that the connection pointer was being cleared. Fixes: 5273a191dca6 ("rxrpc: Fix NULL pointer deref due to call->conn being cleared on disconnect") Signed-off-by: David Howells <dhowells@redhat.com> --- net/rxrpc/conn_object.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)