rxrpc: Fix service call disconnection
[ Upstream commit b39a934ec72fa2b5a74123891f25273a38378b90 ] 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> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
a3623db43a
commit
06748661c7
1 changed files with 1 additions and 2 deletions
|
@ -174,8 +174,6 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
|
||||||
|
|
||||||
_enter("%d,%x", conn->debug_id, call->cid);
|
_enter("%d,%x", conn->debug_id, call->cid);
|
||||||
|
|
||||||
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
|
|
||||||
|
|
||||||
if (rcu_access_pointer(chan->call) == call) {
|
if (rcu_access_pointer(chan->call) == call) {
|
||||||
/* Save the result of the call so that we can repeat it if necessary
|
/* Save the result of the call so that we can repeat it if necessary
|
||||||
* through the channel, whilst disposing of the actual call record.
|
* through the channel, whilst disposing of the actual call record.
|
||||||
|
@ -228,6 +226,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
|
||||||
__rxrpc_disconnect_call(conn, call);
|
__rxrpc_disconnect_call(conn, call);
|
||||||
spin_unlock(&conn->channel_lock);
|
spin_unlock(&conn->channel_lock);
|
||||||
|
|
||||||
|
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
|
||||||
conn->idle_timestamp = jiffies;
|
conn->idle_timestamp = jiffies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue