Skip to content

Commit 42f229c

Browse files
committed
rxrpc: Fix incoming call setup race
An incoming call can race with rxrpc socket destruction, leading to a leaked call. This may result in an oops when the call timer eventually expires: BUG: kernel NULL pointer dereference, address: 0000000000000874 RIP: 0010:_raw_spin_lock_irqsave+0x2a/0x50 Call Trace: <IRQ> try_to_wake_up+0x59/0x550 ? __local_bh_enable_ip+0x37/0x80 ? rxrpc_poke_call+0x52/0x110 [rxrpc] ? rxrpc_poke_call+0x110/0x110 [rxrpc] ? rxrpc_poke_call+0x110/0x110 [rxrpc] call_timer_fn+0x24/0x120 with a warning in the kernel log looking something like: rxrpc: Call 00000000ba5e571a still in use (1,SvAwtACK,1061d,0)! incurred during rmmod of rxrpc. The 1061d is the call flags: RECVMSG_READ_ALL, RX_HEARD, BEGAN_RX_TIMER, RX_LAST, EXPOSED, IS_SERVICE, RELEASED but no DISCONNECTED flag (0x800), so it's an incoming (service) call and it's still connected. The race appears to be that: (1) rxrpc_new_incoming_call() consults the service struct, checks sk_state and allocates a call - then pauses, possibly for an interrupt. (2) rxrpc_release_sock() sets RXRPC_CLOSE, nulls the service pointer, discards the prealloc and releases all calls attached to the socket. (3) rxrpc_new_incoming_call() resumes, launching the new call, including its timer and attaching it to the socket. Fix this by read-locking local->services_lock to access the AF_RXRPC socket providing the service rather than RCU in rxrpc_new_incoming_call(). There's no real need to use RCU here as local->services_lock is only write-locked by the socket side in two places: when binding and when shutting down. Fixes: 5e6ef4f ("rxrpc: Make the I/O thread take over the call and local processor work") Reported-by: Marc Dionne <[email protected]> Signed-off-by: David Howells <[email protected]> cc: [email protected]
1 parent 9d35d88 commit 42f229c

File tree

4 files changed

+15
-15
lines changed

4 files changed

+15
-15
lines changed

net/rxrpc/af_rxrpc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len)
155155

156156
if (service_id) {
157157
write_lock(&local->services_lock);
158-
if (rcu_access_pointer(local->service))
158+
if (local->service)
159159
goto service_in_use;
160160
rx->local = local;
161-
rcu_assign_pointer(local->service, rx);
161+
local->service = rx;
162162
write_unlock(&local->services_lock);
163163

164164
rx->sk.sk_state = RXRPC_SERVER_BOUND;
@@ -875,9 +875,9 @@ static int rxrpc_release_sock(struct sock *sk)
875875

876876
sk->sk_state = RXRPC_CLOSE;
877877

878-
if (rx->local && rcu_access_pointer(rx->local->service) == rx) {
878+
if (rx->local && rx->local->service == rx) {
879879
write_lock(&rx->local->services_lock);
880-
rcu_assign_pointer(rx->local->service, NULL);
880+
rx->local->service = NULL;
881881
write_unlock(&rx->local->services_lock);
882882
}
883883

net/rxrpc/ar-internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ struct rxrpc_local {
283283
struct socket *socket; /* my UDP socket */
284284
struct task_struct *io_thread;
285285
struct completion io_thread_ready; /* Indication that the I/O thread started */
286-
struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */
286+
struct rxrpc_sock *service; /* Service(s) listening on this endpoint */
287287
struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */
288288
struct sk_buff_head rx_queue; /* Received packets */
289289
struct list_head conn_attend_q; /* Conns requiring immediate attention */

net/rxrpc/call_accept.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,13 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
343343
if (sp->hdr.type != RXRPC_PACKET_TYPE_DATA)
344344
return rxrpc_protocol_error(skb, rxrpc_eproto_no_service_call);
345345

346-
rcu_read_lock();
346+
read_lock(&local->services_lock);
347347

348348
/* Weed out packets to services we're not offering. Packets that would
349349
* begin a call are explicitly rejected and the rest are just
350350
* discarded.
351351
*/
352-
rx = rcu_dereference(local->service);
352+
rx = local->service;
353353
if (!rx || (sp->hdr.serviceId != rx->srx.srx_service &&
354354
sp->hdr.serviceId != rx->second_service)
355355
) {
@@ -399,7 +399,7 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
399399
spin_unlock(&conn->state_lock);
400400

401401
spin_unlock(&rx->incoming_lock);
402-
rcu_read_unlock();
402+
read_unlock(&local->services_lock);
403403

404404
if (hlist_unhashed(&call->error_link)) {
405405
spin_lock(&call->peer->lock);
@@ -413,20 +413,20 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
413413
return true;
414414

415415
unsupported_service:
416-
rcu_read_unlock();
416+
read_unlock(&local->services_lock);
417417
return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
418418
RX_INVALID_OPERATION, -EOPNOTSUPP);
419419
unsupported_security:
420-
rcu_read_unlock();
420+
read_unlock(&local->services_lock);
421421
return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
422422
RX_INVALID_OPERATION, -EKEYREJECTED);
423423
no_call:
424424
spin_unlock(&rx->incoming_lock);
425-
rcu_read_unlock();
425+
read_unlock(&local->services_lock);
426426
_leave(" = f [%u]", skb->mark);
427427
return false;
428428
discard:
429-
rcu_read_unlock();
429+
read_unlock(&local->services_lock);
430430
return true;
431431
}
432432

net/rxrpc/security.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
178178
sprintf(kdesc, "%u:%u",
179179
sp->hdr.serviceId, sp->hdr.securityIndex);
180180

181-
rcu_read_lock();
181+
read_lock(&conn->local->services_lock);
182182

183-
rx = rcu_dereference(conn->local->service);
183+
rx = conn->local->service;
184184
if (!rx)
185185
goto out;
186186

@@ -202,6 +202,6 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
202202
}
203203

204204
out:
205-
rcu_read_unlock();
205+
read_unlock(&conn->local->services_lock);
206206
return key;
207207
}

0 commit comments

Comments
 (0)