rxrpc: Fix a potential NULL-pointer deref in rxrpc_abort_calls
authorDavid Howells <dhowells@redhat.com>
Tue, 30 Aug 2016 08:49:28 +0000 (09:49 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 30 Aug 2016 14:56:12 +0000 (15:56 +0100)
The call pointer in a channel on a connection will be NULL if there's no
active call on that channel.  rxrpc_abort_calls() needs to check for this
before trying to take the call's state_lock.

Signed-off-by: David Howells <dhowells@redhat.com>
net/rxrpc/conn_event.c

index 6296374..bb81801 100644 (file)
@@ -149,19 +149,23 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, int state,
                call = rcu_dereference_protected(
                        conn->channels[i].call,
                        lockdep_is_held(&conn->channel_lock));
-               write_lock_bh(&call->state_lock);
-               if (call->state <= RXRPC_CALL_COMPLETE) {
-                       call->state = state;
-                       if (state == RXRPC_CALL_LOCALLY_ABORTED) {
-                               call->local_abort = conn->local_abort;
-                               set_bit(RXRPC_CALL_EV_CONN_ABORT, &call->events);
-                       } else {
-                               call->remote_abort = conn->remote_abort;
-                               set_bit(RXRPC_CALL_EV_RCVD_ABORT, &call->events);
+               if (call) {
+                       write_lock_bh(&call->state_lock);
+                       if (call->state <= RXRPC_CALL_COMPLETE) {
+                               call->state = state;
+                               if (state == RXRPC_CALL_LOCALLY_ABORTED) {
+                                       call->local_abort = conn->local_abort;
+                                       set_bit(RXRPC_CALL_EV_CONN_ABORT,
+                                               &call->events);
+                               } else {
+                                       call->remote_abort = conn->remote_abort;
+                                       set_bit(RXRPC_CALL_EV_RCVD_ABORT,
+                                               &call->events);
+                               }
+                               rxrpc_queue_call(call);
                        }
-                       rxrpc_queue_call(call);
+                       write_unlock_bh(&call->state_lock);
                }
-               write_unlock_bh(&call->state_lock);
        }
 
        spin_unlock(&conn->channel_lock);