Skip to content

Commit 3d80c65

Browse files
committed
Merge tag 'rxrpc-fixes-20200203' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
David Howells says: ==================== RxRPC fixes Here are a number of fixes for AF_RXRPC: (1) Fix a potential use after free in rxrpc_put_local() where it was accessing the object just put to get tracing information. (2) Fix insufficient notifications being generated by the function that queues data packets on a call. This occasionally causes recvmsg() to stall indefinitely. (3) Fix a number of packet-transmitting work functions to hold an active count on the local endpoint so that the UDP socket doesn't get destroyed whilst they're calling kernel_sendmsg() on it. (4) Fix a NULL pointer deref that stemmed from a call's connection pointer being cleared when the call was disconnected. Changes: v2: Removed a couple of BUG() statements that got added. ==================== Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 83d0585 + 5273a19 commit 3d80c65

File tree

10 files changed

+83
-69
lines changed

10 files changed

+83
-69
lines changed

net/rxrpc/af_rxrpc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
194194
service_in_use:
195195
write_unlock(&local->services_lock);
196196
rxrpc_unuse_local(local);
197+
rxrpc_put_local(local);
197198
ret = -EADDRINUSE;
198199
error_unlock:
199200
release_sock(&rx->sk);
@@ -899,6 +900,7 @@ static int rxrpc_release_sock(struct sock *sk)
899900
rxrpc_purge_queue(&sk->sk_receive_queue);
900901

901902
rxrpc_unuse_local(rx->local);
903+
rxrpc_put_local(rx->local);
902904
rx->local = NULL;
903905
key_put(rx->key);
904906
rx->key = NULL;

net/rxrpc/ar-internal.h

Lines changed: 11 additions & 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
/*
@@ -1021,6 +1022,16 @@ void rxrpc_unuse_local(struct rxrpc_local *);
10211022
void rxrpc_queue_local(struct rxrpc_local *);
10221023
void rxrpc_destroy_all_locals(struct rxrpc_net *);
10231024

1025+
static inline bool __rxrpc_unuse_local(struct rxrpc_local *local)
1026+
{
1027+
return atomic_dec_return(&local->active_users) == 0;
1028+
}
1029+
1030+
static inline bool __rxrpc_use_local(struct rxrpc_local *local)
1031+
{
1032+
return atomic_fetch_add_unless(&local->active_users, 1, 0) != 0;
1033+
}
1034+
10241035
/*
10251036
* misc.c
10261037
*/

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_event.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -438,16 +438,12 @@ static void rxrpc_process_delayed_final_acks(struct rxrpc_connection *conn)
438438
/*
439439
* connection-level event processor
440440
*/
441-
void rxrpc_process_connection(struct work_struct *work)
441+
static void rxrpc_do_process_connection(struct rxrpc_connection *conn)
442442
{
443-
struct rxrpc_connection *conn =
444-
container_of(work, struct rxrpc_connection, processor);
445443
struct sk_buff *skb;
446444
u32 abort_code = RX_PROTOCOL_ERROR;
447445
int ret;
448446

449-
rxrpc_see_connection(conn);
450-
451447
if (test_and_clear_bit(RXRPC_CONN_EV_CHALLENGE, &conn->events))
452448
rxrpc_secure_connection(conn);
453449

@@ -475,18 +471,32 @@ void rxrpc_process_connection(struct work_struct *work)
475471
}
476472
}
477473

478-
out:
479-
rxrpc_put_connection(conn);
480-
_leave("");
481474
return;
482475

483476
requeue_and_leave:
484477
skb_queue_head(&conn->rx_queue, skb);
485-
goto out;
478+
return;
486479

487480
protocol_error:
488481
if (rxrpc_abort_connection(conn, ret, abort_code) < 0)
489482
goto requeue_and_leave;
490483
rxrpc_free_skb(skb, rxrpc_skb_freed);
491-
goto out;
484+
return;
485+
}
486+
487+
void rxrpc_process_connection(struct work_struct *work)
488+
{
489+
struct rxrpc_connection *conn =
490+
container_of(work, struct rxrpc_connection, processor);
491+
492+
rxrpc_see_connection(conn);
493+
494+
if (__rxrpc_use_local(conn->params.local)) {
495+
rxrpc_do_process_connection(conn);
496+
rxrpc_unuse_local(conn->params.local);
497+
}
498+
499+
rxrpc_put_connection(conn);
500+
_leave("");
501+
return;
492502
}

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/input.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -599,10 +599,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
599599
false, true,
600600
rxrpc_propose_ack_input_data);
601601

602-
if (seq0 == READ_ONCE(call->rx_hard_ack) + 1) {
603-
trace_rxrpc_notify_socket(call->debug_id, serial);
604-
rxrpc_notify_socket(call);
605-
}
602+
trace_rxrpc_notify_socket(call->debug_id, serial);
603+
rxrpc_notify_socket(call);
606604

607605
unlock:
608606
spin_unlock(&call->input_lock);

net/rxrpc/local_object.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -364,11 +364,14 @@ void rxrpc_queue_local(struct rxrpc_local *local)
364364
void rxrpc_put_local(struct rxrpc_local *local)
365365
{
366366
const void *here = __builtin_return_address(0);
367+
unsigned int debug_id;
367368
int n;
368369

369370
if (local) {
371+
debug_id = local->debug_id;
372+
370373
n = atomic_dec_return(&local->usage);
371-
trace_rxrpc_local(local->debug_id, rxrpc_local_put, n, here);
374+
trace_rxrpc_local(debug_id, rxrpc_local_put, n, here);
372375

373376
if (n == 0)
374377
call_rcu(&local->rcu, rxrpc_local_rcu);
@@ -380,14 +383,11 @@ void rxrpc_put_local(struct rxrpc_local *local)
380383
*/
381384
struct rxrpc_local *rxrpc_use_local(struct rxrpc_local *local)
382385
{
383-
unsigned int au;
384-
385386
local = rxrpc_get_local_maybe(local);
386387
if (!local)
387388
return NULL;
388389

389-
au = atomic_fetch_add_unless(&local->active_users, 1, 0);
390-
if (au == 0) {
390+
if (!__rxrpc_use_local(local)) {
391391
rxrpc_put_local(local);
392392
return NULL;
393393
}
@@ -401,14 +401,11 @@ struct rxrpc_local *rxrpc_use_local(struct rxrpc_local *local)
401401
*/
402402
void rxrpc_unuse_local(struct rxrpc_local *local)
403403
{
404-
unsigned int au;
405-
406404
if (local) {
407-
au = atomic_dec_return(&local->active_users);
408-
if (au == 0)
405+
if (__rxrpc_unuse_local(local)) {
406+
rxrpc_get_local(local);
409407
rxrpc_queue_local(local);
410-
else
411-
rxrpc_put_local(local);
408+
}
412409
}
413410
}
414411

@@ -465,7 +462,7 @@ static void rxrpc_local_processor(struct work_struct *work)
465462

466463
do {
467464
again = false;
468-
if (atomic_read(&local->active_users) == 0) {
465+
if (!__rxrpc_use_local(local)) {
469466
rxrpc_local_destroyer(local);
470467
break;
471468
}
@@ -479,6 +476,8 @@ static void rxrpc_local_processor(struct work_struct *work)
479476
rxrpc_process_local_events(local);
480477
again = true;
481478
}
479+
480+
__rxrpc_unuse_local(local);
482481
} while (again);
483482

484483
rxrpc_put_local(local);

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

net/rxrpc/peer_event.c

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -364,27 +364,31 @@ static void rxrpc_peer_keepalive_dispatch(struct rxrpc_net *rxnet,
364364
if (!rxrpc_get_peer_maybe(peer))
365365
continue;
366366

367-
spin_unlock_bh(&rxnet->peer_hash_lock);
368-
369-
keepalive_at = peer->last_tx_at + RXRPC_KEEPALIVE_TIME;
370-
slot = keepalive_at - base;
371-
_debug("%02x peer %u t=%d {%pISp}",
372-
cursor, peer->debug_id, slot, &peer->srx.transport);
367+
if (__rxrpc_use_local(peer->local)) {
368+
spin_unlock_bh(&rxnet->peer_hash_lock);
369+
370+
keepalive_at = peer->last_tx_at + RXRPC_KEEPALIVE_TIME;
371+
slot = keepalive_at - base;
372+
_debug("%02x peer %u t=%d {%pISp}",
373+
cursor, peer->debug_id, slot, &peer->srx.transport);
374+
375+
if (keepalive_at <= base ||
376+
keepalive_at > base + RXRPC_KEEPALIVE_TIME) {
377+
rxrpc_send_keepalive(peer);
378+
slot = RXRPC_KEEPALIVE_TIME;
379+
}
373380

374-
if (keepalive_at <= base ||
375-
keepalive_at > base + RXRPC_KEEPALIVE_TIME) {
376-
rxrpc_send_keepalive(peer);
377-
slot = RXRPC_KEEPALIVE_TIME;
381+
/* A transmission to this peer occurred since last we
382+
* examined it so put it into the appropriate future
383+
* bucket.
384+
*/
385+
slot += cursor;
386+
slot &= mask;
387+
spin_lock_bh(&rxnet->peer_hash_lock);
388+
list_add_tail(&peer->keepalive_link,
389+
&rxnet->peer_keepalive[slot & mask]);
390+
rxrpc_unuse_local(peer->local);
378391
}
379-
380-
/* A transmission to this peer occurred since last we examined
381-
* it so put it into the appropriate future bucket.
382-
*/
383-
slot += cursor;
384-
slot &= mask;
385-
spin_lock_bh(&rxnet->peer_hash_lock);
386-
list_add_tail(&peer->keepalive_link,
387-
&rxnet->peer_keepalive[slot & mask]);
388392
rxrpc_put_peer_locked(peer);
389393
}
390394

0 commit comments

Comments
 (0)