Skip to content

Commit 5273a19

Browse files
committed
rxrpc: Fix NULL pointer deref due to call->conn being cleared on disconnect
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]>
1 parent 04d36d7 commit 5273a19

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
@@ -490,6 +490,7 @@ enum rxrpc_call_flag {
490490
RXRPC_CALL_RX_HEARD, /* The peer responded at least once to this call */
491491
RXRPC_CALL_RX_UNDERRUN, /* Got data underrun */
492492
RXRPC_CALL_IS_INTR, /* The call is interruptible */
493+
RXRPC_CALL_DISCONNECTED, /* The call has been disconnected */
493494
};
494495

495496
/*

net/rxrpc/call_object.c

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

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

496-
if (conn)
496+
if (conn && !test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
497497
rxrpc_disconnect_call(call);
498498
if (call->security)
499499
call->security->free_call_crypto(call);
@@ -569,6 +569,7 @@ static void rxrpc_rcu_destroy_call(struct rcu_head *rcu)
569569
struct rxrpc_call *call = container_of(rcu, struct rxrpc_call, rcu);
570570
struct rxrpc_net *rxnet = call->rxnet;
571571

572+
rxrpc_put_connection(call->conn);
572573
rxrpc_put_peer(call->peer);
573574
kfree(call->rxtx_buffer);
574575
kfree(call->rxtx_annotations);
@@ -590,7 +591,6 @@ void rxrpc_cleanup_call(struct rxrpc_call *call)
590591

591592
ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
592593
ASSERT(test_bit(RXRPC_CALL_RELEASED, &call->flags));
593-
ASSERTCMP(call->conn, ==, NULL);
594594

595595
rxrpc_cleanup_ring(call);
596596
rxrpc_free_skb(call->tx_pending, rxrpc_skb_cleaned);

net/rxrpc/conn_client.c

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

787787
spin_lock(&conn->channel_lock);
788+
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
788789

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

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

net/rxrpc/conn_object.c

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

172172
_enter("%d,%x", conn->debug_id, call->cid);
173173

174+
set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
175+
174176
if (rcu_access_pointer(chan->call) == call) {
175177
/* Save the result of the call so that we can repeat it if necessary
176178
* through the channel, whilst disposing of the actual call record.
@@ -223,9 +225,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
223225
__rxrpc_disconnect_call(conn, call);
224226
spin_unlock(&conn->channel_lock);
225227

226-
call->conn = NULL;
227228
conn->idle_timestamp = jiffies;
228-
rxrpc_put_connection(conn);
229229
}
230230

231231
/*

net/rxrpc/output.c

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
129129
int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
130130
rxrpc_serial_t *_serial)
131131
{
132-
struct rxrpc_connection *conn = NULL;
132+
struct rxrpc_connection *conn;
133133
struct rxrpc_ack_buffer *pkt;
134134
struct msghdr msg;
135135
struct kvec iov[2];
@@ -139,18 +139,14 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
139139
int ret;
140140
u8 reason;
141141

142-
spin_lock_bh(&call->lock);
143-
if (call->conn)
144-
conn = rxrpc_get_connection_maybe(call->conn);
145-
spin_unlock_bh(&call->lock);
146-
if (!conn)
142+
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
147143
return -ECONNRESET;
148144

149145
pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
150-
if (!pkt) {
151-
rxrpc_put_connection(conn);
146+
if (!pkt)
152147
return -ENOMEM;
153-
}
148+
149+
conn = call->conn;
154150

155151
msg.msg_name = &call->peer->srx.transport;
156152
msg.msg_namelen = call->peer->srx.transport_len;
@@ -244,7 +240,6 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
244240
}
245241

246242
out:
247-
rxrpc_put_connection(conn);
248243
kfree(pkt);
249244
return ret;
250245
}
@@ -254,7 +249,7 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
254249
*/
255250
int rxrpc_send_abort_packet(struct rxrpc_call *call)
256251
{
257-
struct rxrpc_connection *conn = NULL;
252+
struct rxrpc_connection *conn;
258253
struct rxrpc_abort_buffer pkt;
259254
struct msghdr msg;
260255
struct kvec iov[1];
@@ -271,13 +266,11 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
271266
test_bit(RXRPC_CALL_TX_LAST, &call->flags))
272267
return 0;
273268

274-
spin_lock_bh(&call->lock);
275-
if (call->conn)
276-
conn = rxrpc_get_connection_maybe(call->conn);
277-
spin_unlock_bh(&call->lock);
278-
if (!conn)
269+
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
279270
return -ECONNRESET;
280271

272+
conn = call->conn;
273+
281274
msg.msg_name = &call->peer->srx.transport;
282275
msg.msg_namelen = call->peer->srx.transport_len;
283276
msg.msg_control = NULL;
@@ -312,8 +305,6 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
312305
trace_rxrpc_tx_packet(call->debug_id, &pkt.whdr,
313306
rxrpc_tx_point_call_abort);
314307
rxrpc_tx_backoff(call, ret);
315-
316-
rxrpc_put_connection(conn);
317308
return ret;
318309
}
319310

0 commit comments

Comments
 (0)