linux/net
Daniel Borkmann 1e1cdf8ac7 net: sctp: test if association is dead in sctp_wake_up_waiters
In function sctp_wake_up_waiters(), we need to involve a test
if the association is declared dead. If so, we don't have any
reference to a possible sibling association anymore and need
to invoke sctp_write_space() instead, and normally walk the
socket's associations and notify them of new wmem space. The
reason for special casing is that otherwise, we could run
into the following issue when a sctp_primitive_SEND() call
from sctp_sendmsg() fails, and tries to flush an association's
outq, i.e. in the following way:

sctp_association_free()
`-> list_del(&asoc->asocs)         <-- poisons list pointer
    asoc->base.dead = true
    sctp_outq_free(&asoc->outqueue)
    `-> __sctp_outq_teardown()
     `-> sctp_chunk_free()
      `-> consume_skb()
       `-> sctp_wfree()
        `-> sctp_wake_up_waiters() <-- dereferences poisoned pointers
                                       if asoc->ep->sndbuf_policy=0

Therefore, only walk the list in an 'optimized' way if we find
that the current association is still active. We could also use
list_del_init() in addition when we call sctp_association_free(),
but as Vlad suggests, we want to trap such bugs and thus leave
it poisoned as is.

Why is it safe to resolve the issue by testing for asoc->base.dead?
Parallel calls to sctp_sendmsg() are protected under socket lock,
that is lock_sock()/release_sock(). Only within that path under
lock held, we're setting skb/chunk owner via sctp_set_owner_w().
Eventually, chunks are freed directly by an association still
under that lock. So when traversing association list on destruction
time from sctp_wake_up_waiters() via sctp_wfree(), a different
CPU can't be running sctp_wfree() while another one calls
sctp_association_free() as both happens under the same lock.
Therefore, this can also not race with setting/testing against
asoc->base.dead as we are guaranteed for this to happen in order,
under lock. Further, Vlad says: the times we check asoc->base.dead
is when we've cached an association pointer for later processing.
In between cache and processing, the association may have been
freed and is simply still around due to reference counts. We check
asoc->base.dead under a lock, so it should always be safe to check
and not race against sctp_association_free(). Stress-testing seems
fine now, too.

Fixes: cd253f9f357d ("net: sctp: wake up all assocs if sndbuf policy is per socket")
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Cc: Vlad Yasevich <vyasevic@redhat.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2014-04-09 12:37:49 -04:00
..
9p
802
8021q Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-03-29 18:48:54 -04:00
appletalk
atm atm: replace del_timer by del_timer_sync 2014-03-27 15:28:06 -04:00
ax25
batman-adv batman-adv: Start new development cycle 2014-03-22 09:18:59 +01:00
bluetooth Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next 2014-04-02 20:53:45 -07:00
bridge netfilter: Can't fail and free after table replacement 2014-04-05 17:46:22 +02:00
caif
can can: remove CAN FD compatibility for CAN 2.0 sockets 2014-03-03 14:29:52 +01:00
ceph Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client 2014-04-07 11:09:13 -07:00
core Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-04-08 12:41:23 -07:00
dcb
dccp
decnet
dns_resolver
dsa
ethernet
hsr hsr: replace del_timer by del_timer_sync 2014-03-27 15:28:06 -04:00
ieee802154 mac802154: make csma/cca parameters per-wpan 2014-04-01 16:25:51 -04:00
ipv4 Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-04-08 12:41:23 -07:00
ipv6 netfilter: Can't fail and free after table replacement 2014-04-05 17:46:22 +02:00
ipx
irda
iucv Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux 2014-04-08 12:02:28 -07:00
key Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-03-25 20:29:20 -04:00
l2tp Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next 2014-04-02 20:53:45 -07:00
lapb
llc
mac80211 Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem 2014-03-21 14:02:04 -04:00
mac802154 mac802154: fix duplicate #include headers 2014-04-07 13:18:44 -04:00
mpls
netfilter netfilter: nf_tables: fix wrong format in request_module() 2014-04-03 23:52:50 +02:00
netlabel
netlink netlink: autosize skb lengthes 2014-03-10 13:56:26 -04:00
netrom
nfc NFC: 3.15: First pull request 2014-03-17 13:16:50 -04:00
openvswitch Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-03-29 18:48:54 -04:00
packet packet: fix packet_direct_xmit for BQL enabled drivers 2014-04-03 14:29:12 -04:00
phonet
rds rds: prevent dereference of a NULL device in rds_iw_laddr_check 2014-03-31 16:25:52 -04:00
rfkill
rose
rxrpc af_rxrpc: Keep rxrpc_call pointers in a hashtable 2014-03-04 10:36:53 +00:00
sched net-sysfs: expose number of carrier on/off changes 2014-03-31 16:24:52 -04:00
sctp net: sctp: test if association is dead in sctp_wake_up_waiters 2014-04-09 12:37:49 -04:00
sunrpc NFS client updates for Linux 3.15 2014-04-06 10:09:38 -07:00
tipc tipc: Let tipc_release() return 0 2014-04-07 15:08:17 -04:00
unix net: unix: non blocking recvmsg() should not return -EINTR 2014-03-26 17:05:40 -04:00
vmw_vsock
wimax
wireless Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem 2014-03-21 14:02:04 -04:00
x25
xfrm Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net 2014-03-25 20:29:20 -04:00
compat.c net/compat: convert to COMPAT_SYSCALL_DEFINE with changing parameter types 2014-03-06 16:30:45 +01:00
Kconfig Merge branch 'for-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup 2014-04-03 13:05:42 -07:00
Makefile
nonet.c
socket.c net: ptp: move PTP classifier in its own file 2014-04-01 16:43:18 -04:00
sysctl_net.c