aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-10-07 05:58:29 -0400
committerDavid Howells <dhowells@redhat.com>2019-10-07 06:05:05 -0400
commit55f6c98e3674ce16038a1949c3f9ca5a9a99f289 (patch)
tree83abbc62305d829243847ef9a83e4074560ef20e /net
parentc48fc11b69e95007109206311b0187a3090591f3 (diff)
rxrpc: Fix trace-after-put looking at the put peer record
rxrpc_put_peer() calls trace_rxrpc_peer() after it has done the decrement of the refcount - which looks at the debug_id in the peer record. But unless the refcount was reduced to zero, we no longer have the right to look in the record and, indeed, it may be deleted by some other thread. Fix this by getting the debug_id out before decrementing the refcount and then passing that into the tracepoint. This can cause the following symptoms: BUG: KASAN: use-after-free in __rxrpc_put_peer net/rxrpc/peer_object.c:411 [inline] BUG: KASAN: use-after-free in rxrpc_put_peer+0x685/0x6a0 net/rxrpc/peer_object.c:435 Read of size 8 at addr ffff888097ec0058 by task syz-executor823/24216 Fixes: 1159d4b496f5 ("rxrpc: Add a tracepoint to track rxrpc_peer refcounting") Reported-by: syzbot+b9be979c55f2bea8ed30@syzkaller.appspotmail.com Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/rxrpc/peer_object.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c
index 9c3ac96f71cb..b700b7ecaa3d 100644
--- a/net/rxrpc/peer_object.c
+++ b/net/rxrpc/peer_object.c
@@ -382,7 +382,7 @@ struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer)
382 int n; 382 int n;
383 383
384 n = atomic_inc_return(&peer->usage); 384 n = atomic_inc_return(&peer->usage);
385 trace_rxrpc_peer(peer, rxrpc_peer_got, n, here); 385 trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, n, here);
386 return peer; 386 return peer;
387} 387}
388 388
@@ -396,7 +396,7 @@ struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *peer)
396 if (peer) { 396 if (peer) {
397 int n = atomic_fetch_add_unless(&peer->usage, 1, 0); 397 int n = atomic_fetch_add_unless(&peer->usage, 1, 0);
398 if (n > 0) 398 if (n > 0)
399 trace_rxrpc_peer(peer, rxrpc_peer_got, n + 1, here); 399 trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, n + 1, here);
400 else 400 else
401 peer = NULL; 401 peer = NULL;
402 } 402 }
@@ -426,11 +426,13 @@ static void __rxrpc_put_peer(struct rxrpc_peer *peer)
426void rxrpc_put_peer(struct rxrpc_peer *peer) 426void rxrpc_put_peer(struct rxrpc_peer *peer)
427{ 427{
428 const void *here = __builtin_return_address(0); 428 const void *here = __builtin_return_address(0);
429 unsigned int debug_id;
429 int n; 430 int n;
430 431
431 if (peer) { 432 if (peer) {
433 debug_id = peer->debug_id;
432 n = atomic_dec_return(&peer->usage); 434 n = atomic_dec_return(&peer->usage);
433 trace_rxrpc_peer(peer, rxrpc_peer_put, n, here); 435 trace_rxrpc_peer(debug_id, rxrpc_peer_put, n, here);
434 if (n == 0) 436 if (n == 0)
435 __rxrpc_put_peer(peer); 437 __rxrpc_put_peer(peer);
436 } 438 }
@@ -443,10 +445,11 @@ void rxrpc_put_peer(struct rxrpc_peer *peer)
443void rxrpc_put_peer_locked(struct rxrpc_peer *peer) 445void rxrpc_put_peer_locked(struct rxrpc_peer *peer)
444{ 446{
445 const void *here = __builtin_return_address(0); 447 const void *here = __builtin_return_address(0);
448 unsigned int debug_id = peer->debug_id;
446 int n; 449 int n;
447 450
448 n = atomic_dec_return(&peer->usage); 451 n = atomic_dec_return(&peer->usage);
449 trace_rxrpc_peer(peer, rxrpc_peer_put, n, here); 452 trace_rxrpc_peer(debug_id, rxrpc_peer_put, n, here);
450 if (n == 0) { 453 if (n == 0) {
451 hash_del_rcu(&peer->hash_link); 454 hash_del_rcu(&peer->hash_link);
452 list_del_init(&peer->keepalive_link); 455 list_del_init(&peer->keepalive_link);