linux-stable/net/rds
Herton R. Krzesinski 593cbb3ec6 net/rds: fix possible double free on sock tear down
I got a report of a double free happening at RDS slab cache. One
suspicion was that may be somewhere we were doing a sock_hold/sock_put
on an already freed sock. Thus after providing a kernel with the
following change:

 static inline void sock_hold(struct sock *sk)
 {
-       atomic_inc(&sk->sk_refcnt);
+       if (!atomic_inc_not_zero(&sk->sk_refcnt))
+               WARN(1, "Trying to hold sock already gone: %p (family: %hd)\n",
+                       sk, sk->sk_family);
 }

The warning successfuly triggered:

Trying to hold sock already gone: ffff81f6dda61280 (family: 21)
WARNING: at include/net/sock.h:350 sock_hold()
Call Trace:
<IRQ>  [<ffffffff8adac135>] :rds:rds_send_remove_from_sock+0xf0/0x21b
[<ffffffff8adad35c>] :rds:rds_send_drop_acked+0xbf/0xcf
[<ffffffff8addf546>] :rds_rdma:rds_ib_recv_tasklet_fn+0x256/0x2dc
[<ffffffff8009899a>] tasklet_action+0x8f/0x12b
[<ffffffff800125a2>] __do_softirq+0x89/0x133
[<ffffffff8005f30c>] call_softirq+0x1c/0x28
[<ffffffff8006e644>] do_softirq+0x2c/0x7d
[<ffffffff8006e4d4>] do_IRQ+0xee/0xf7
[<ffffffff8005e625>] ret_from_intr+0x0/0xa
<EOI>

Looking at the call chain above, the only way I think this would be
possible is if somewhere we already released the same socket->sock which
is assigned to the rds_message at rds_send_remove_from_sock. Which seems
only possible to happen after the tear down done on rds_release.

rds_release properly calls rds_send_drop_to to drop the socket from any
rds_message, and some proper synchronization is in place to avoid race
with rds_send_drop_acked/rds_send_remove_from_sock. However, I still see
a very narrow window where it may be possible we touch a sock already
released: when rds_release races with rds_send_drop_acked, we check
RDS_MSG_ON_CONN to avoid cleanup on the same rds_message, but in this
specific case we don't clear rm->m_rs. In this case, it seems we could
then go on at rds_send_drop_to and after it returns, the sock is freed
by last sock_put on rds_release, with concurrently we being at
rds_send_remove_from_sock; then at some point in the loop at
rds_send_remove_from_sock we process an rds_message which didn't have
rm->m_rs unset for a freed sock, and a possible sock_hold on an sock
already gone at rds_release happens.

This hopefully address the described condition above and avoids a double
free on "second last" sock_put. In addition, I removed the comment about
socket destruction on top of rds_send_drop_acked: we call rds_send_drop_to
in rds_release and we should have things properly serialized there, thus
I can't see the comment being accurate there.

Signed-off-by: Herton R. Krzesinski <herton@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-10-03 12:52:00 -07:00
..
af_rds.c rds: Make rds_sock_lock BH rather than IRQ safe. 2012-01-24 17:03:44 -05:00
bind.c net: replace macros net_random and net_srandom with direct calls to prandom 2014-01-14 15:15:25 -08:00
cong.c net: Add export.h for EXPORT_SYMBOL/THIS_MODULE to non-modules 2011-10-31 19:30:30 -04:00
connection.c inet: convert inet_ehash_secret and ipv6_hash_secret to net_get_random_once 2013-10-19 19:45:35 -04:00
ib.c rds: prevent dereference of a NULL device 2013-12-27 12:33:58 -05:00
ib.h net: rds: use this_cpu_* per-cpu helper 2012-11-19 18:59:44 -05:00
ib_cm.c IB/rds: suppress incompatible protocol when version is known 2012-12-26 15:17:37 -08:00
ib_rdma.c net, rds, Replace xlist in net/rds/xlist.h with llist 2011-09-15 15:36:32 -04:00
ib_recv.c arch: Mass conversion of smp_mb__*() 2014-04-18 14:20:48 +02:00
ib_ring.c
ib_send.c net: rds: Use time_after() for time comparison 2014-05-18 21:24:52 -04:00
ib_stats.c
ib_sysctl.c net: Convert uses of typedef ctl_table to struct ctl_table 2013-06-13 02:36:09 -07:00
info.c rds: remove the second argument of k[un]map_atomic() 2012-03-20 21:48:28 +08:00
info.h
iw.c rds: prevent dereference of a NULL device in rds_iw_laddr_check 2014-03-31 16:25:52 -04:00
iw.h net: remove interrupt.h inclusion from netdevice.h 2011-06-06 22:55:11 -07:00
iw_cm.c RDS: use gfp flags from caller in conn_alloc() 2012-03-22 19:29:58 -04:00
iw_rdma.c RDS: Remove some unused iWARP code 2012-01-12 20:05:28 -08:00
iw_recv.c arch: Mass conversion of smp_mb__*() 2014-04-18 14:20:48 +02:00
iw_ring.c
iw_send.c net: rds: Use time_after() for time comparison 2014-05-18 21:24:52 -04:00
iw_stats.c
iw_sysctl.c rds: remove the unneed NULL checking 2014-05-09 15:59:45 -04:00
Kconfig net/rds: remove depends on CONFIG_EXPERIMENTAL 2013-01-11 11:40:02 -08:00
loop.c RDS: use gfp flags from caller in conn_alloc() 2012-03-22 19:29:58 -04:00
loop.h
Makefile Net: rds: Makefile: Remove deprecated items 2010-11-22 08:16:15 -08:00
message.c rds: simplify a warning message 2013-03-04 14:12:07 -05:00
page.c net: Fix (nearly-)kernel-doc comments for various functions 2012-07-10 23:13:45 -07:00
rdma.c rds: Integer overflow in RDS cmsg handling 2010-11-17 12:20:52 -08:00
rdma_transport.c RDS/RDMA: Replace comma with semicolon 2014-05-30 17:48:58 -07:00
rdma_transport.h rds: make local functions/variables static 2010-10-21 04:26:39 -07:00
rds.h net: misc: Remove extern from function prototypes 2013-10-19 19:12:11 -04:00
recv.c net: add build-time checks for msg->msg_name size 2014-01-18 23:04:16 -08:00
send.c net/rds: fix possible double free on sock tear down 2014-10-03 12:52:00 -07:00
stats.c net/rds: zero last byte for strncpy 2013-03-08 00:35:44 -05:00
sysctl.c rds: remove the unneed NULL checking 2014-05-09 15:59:45 -04:00
tcp.c net: Fix files explicitly needing to include module.h 2011-10-31 19:30:28 -04:00
tcp.h net: Fix use after free by removing length arg from sk_data_ready callbacks. 2014-04-11 16:15:36 -04:00
tcp_connect.c net/rds: do proper house keeping if connection fails in rds_tcp_conn_connect 2014-10-03 12:51:59 -07:00
tcp_listen.c rds/tcp_listen: Replace comma with semicolon 2014-05-30 17:48:58 -07:00
tcp_recv.c net: Fix use after free by removing length arg from sk_data_ready callbacks. 2014-04-11 16:15:36 -04:00
tcp_send.c arch: Mass conversion of smp_mb__*() 2014-04-18 14:20:48 +02:00
tcp_stats.c net: rds: fix const array syntax 2011-07-01 16:16:19 -07:00
threads.c net/rds: call rds_conn_drop instead of open code it at rds_connect_complete 2014-10-03 12:51:59 -07:00
transport.c