Skip to content

Commit 22779a2

Browse files
dhowellsgregkh
authored andcommitted
rxrpc: Fix NULL pointer deref due to call->conn being cleared on disconnect
[ Upstream commit 5273a19 ] When a call is disconnected, the connection pointer from the call is cleared to make sure it isn't used again and to prevent further attempted transmission for the call. Unfortunately, there might be a daemon trying to use it at the same time to transmit a packet. Fix this by keeping call->conn set, but setting a flag on the call to indicate disconnection instead. Remove also the bits in the transmission functions where the conn pointer is checked and a ref taken under spinlock as this is now redundant. Fixes: 8d94aa3 ("rxrpc: Calls shouldn't hold socket refs") Signed-off-by: David Howells <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a2562d4 commit 22779a2

File tree

5 files changed

+15
-24
lines changed

5 files changed

+15
-24
lines changed

net/rxrpc/ar-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ enum rxrpc_call_flag {
484484
RXRPC_CALL_BEGAN_RX_TIMER, /* We began the expect_rx_by timer */
485485
RXRPC_CALL_RX_HEARD, /* The peer responded at least once to this call */
486486
RXRPC_CALL_RX_UNDERRUN, /* Got data underrun */
487+
RXRPC_CALL_DISCONNECTED, /* The call has been disconnected */
487488
};
488489

489490
/*

net/rxrpc/call_object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
520520

521521
_debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, conn);
522522

523-
if (conn)
523+
if (conn && !test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
524524
rxrpc_disconnect_call(call);
525525

526526
for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
@@ -654,6 +654,7 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu)
654654
struct rxrpc_call *call = container_of(rcu, struct rxrpc_call, rcu);
655655
struct rxrpc_net *rxnet = call->rxnet;
656656

657+
rxrpc_put_connection(call->conn);
657658
rxrpc_put_peer(call->peer);
658659
kfree(call->rxtx_buffer);
659660
kfree(call->rxtx_annotations);
@@ -677,7 +678,6 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
677678

678679
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
679680
ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
680-
ASSERTCMP(call->conn, ==, NULL);
681681

682682
/* Clean up the Rx/Tx buffer */
683683
for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++)

net/rxrpc/conn_client.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,14 +786,14 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
786786
u32 cid;
787787

788788
spin_lock(&conn->channel_lock);
789+
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
789790

790791
cid = call->cid;
791792
if (cid) {
792793
channel = cid & RXRPC_CHANNELMASK;
793794
chan = &conn->channels[channel];
794795
}
795796
trace_rxrpc_client(conn, channel, rxrpc_client_chan_disconnect);
796-
call->conn = NULL;
797797

798798
/* Calls that have never actually been assigned a channel can simply be
799799
* discarded. If the conn didn't get used either, it will follow
@@ -909,7 +909,6 @@ void rxrpc_disconnect_client_call(struct rxrpc_call *call)
909909
spin_unlock(&rxnet->client_conn_cache_lock);
910910
out_2:
911911
spin_unlock(&conn->channel_lock);
912-
rxrpc_put_connection(conn);
913912
_leave("");
914913
return;
915914

net/rxrpc/conn_object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
174174

175175
_enter("%d,%x", conn->debug_id, call->cid);
176176

177+
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
178+
177179
if (rcu_access_pointer(chan->call) == call) {
178180
/* Save the result of the call so that we can repeat it if necessary
179181
* through the channel, whilst disposing of the actual call record.
@@ -226,9 +228,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
226228
__rxrpc_disconnect_call(conn, call);
227229
spin_unlock(&conn->channel_lock);
228230

229-
call->conn = NULL;
230231
conn->idle_timestamp = jiffies;
231-
rxrpc_put_connection(conn);
232232
}
233233

234234
/*

net/rxrpc/output.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
133133
int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
134134
rxrpc_serial_t *_serial)
135135
{
136-
struct rxrpc_connection *conn = NULL;
136+
struct rxrpc_connection *conn;
137137
struct rxrpc_ack_buffer *pkt;
138138
struct msghdr msg;
139139
struct kvec iov[2];
@@ -143,18 +143,14 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
143143
int ret;
144144
u8 reason;
145145

146-
spin_lock_bh(&call->lock);
147-
if (call->conn)
148-
conn = rxrpc_get_connection_maybe(call->conn);
149-
spin_unlock_bh(&call->lock);
150-
if (!conn)
146+
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
151147
return -ECONNRESET;
152148

153149
pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
154-
if (!pkt) {
155-
rxrpc_put_connection(conn);
150+
if (!pkt)
156151
return -ENOMEM;
157-
}
152+
153+
conn = call->conn;
158154

159155
msg.msg_name = &call->peer->srx.transport;
160156
msg.msg_namelen = call->peer->srx.transport_len;
@@ -249,7 +245,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
249245
}
250246

251247
out:
252-
rxrpc_put_connection(conn);
253248
kfree(pkt);
254249
return ret;
255250
}
@@ -259,7 +254,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
259254
*/
260255
int rxrpc_send_abort_packet(struct rxrpc_call *call)
261256
{
262-
struct rxrpc_connection *conn = NULL;
257+
struct rxrpc_connection *conn;
263258
struct rxrpc_abort_buffer pkt;
264259
struct msghdr msg;
265260
struct kvec iov[1];
@@ -276,13 +271,11 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
276271
test_bit(RXRPC_CALL_TX_LAST, &call->flags))
277272
return 0;
278273

279-
spin_lock_bh(&call->lock);
280-
if (call->conn)
281-
conn = rxrpc_get_connection_maybe(call->conn);
282-
spin_unlock_bh(&call->lock);
283-
if (!conn)
274+
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
284275
return -ECONNRESET;
285276

277+
conn = call->conn;
278+
286279
msg.msg_name = &call->peer->srx.transport;
287280
msg.msg_namelen = call->peer->srx.transport_len;
288281
msg.msg_control = NULL;
@@ -317,8 +310,6 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
317310
trace_rxrpc_tx_packet(call->debug_id, &pkt.whdr,
318311
rxrpc_tx_point_call_abort);
319312
rxrpc_tx_backoff(call, ret);
320-
321-
rxrpc_put_connection(conn);
322313
return ret;
323314
}
324315

0 commit comments

Comments
 (0)