linux/net/sctp
Daniel Borkmann 8c98653f05 sctp: sctp_close: fix release of bindings for deferred call_rcu's
It seems due to RCU usage, i.e. within SCTP's address binding list,
a, say, ``behavioral change'' was introduced which does actually
not conform to the RFC anymore. In particular consider the following
(fictional) scenario to demonstrate this:

  do:
    Two SOCK_SEQPACKET-style sockets are opened (S1, S2)
    S1 is bound to 127.0.0.1, port 1024 [server]
    S2 is bound to 127.0.0.1, port 1025 [client]
    listen(2) is invoked on S1
    From S2 we call one sendmsg(2) with msg.msg_name and
       msg.msg_namelen parameters set to the server's
       address
    S1, S2 are closed
    goto do

The first pass of this loop passes successful, while the second round
fails during binding of S1 (address still in use). What is happening?
In the first round, the initial handshake is being done, and, at the
time close(2) is called on S1, a non-graceful shutdown is performed via
ABORT since in S1's receive queue an unprocessed packet is present,
thus stating an error condition. This can be considered as a correct
behavior.

During close also all bound addresses are freed, thus nothing *must*
be active anymore. In reference to RFC2960:

  After checking the Verification Tag, the receiving endpoint shall
  remove the association from its record, and shall report the
  termination to its upper layer. (9.1 Abort of an Association)

Also, no half-open states are supported, thus after an ungraceful
shutdown, we leave nothing behind. However, this seems not to be
happening though. In a real-world scenario, this is exactly where
it breaks the lksctp-tools functional test suite, *for instance*:

  ./test_sockopt
  test_sockopt.c  1 PASS : getsockopt(SCTP_STATUS) on a socket with no assoc
  test_sockopt.c  2 PASS : getsockopt(SCTP_STATUS)
  test_sockopt.c  3 PASS : getsockopt(SCTP_STATUS) with invalid associd
  test_sockopt.c  4 PASS : getsockopt(SCTP_STATUS) with NULL associd
  test_sockopt.c  5 BROK : bind: Address already in use

The underlying problem is that sctp_endpoint_destroy() hasn't been
triggered yet while the next bind attempt is being done. It will be
triggered eventually (but too late) by sctp_transport_destroy_rcu()
after one RCU grace period:

  sctp_transport_destroy()
    sctp_transport_destroy_rcu() ----.
      sctp_association_put() [*]  <--+--> sctp_packet_free()
        sctp_association_destroy()          [...]
          sctp_endpoint_put()                 skb->destructor
            sctp_endpoint_destroy()             sctp_wfree()
              sctp_bind_addr_free()               sctp_association_put() [*]

Thus, we move out the condition with sctp_association_put() as well as
the sctp_packet_free() invocation and the issue can be solved. We also
better free the SCTP chunks first before putting the ref of the association.

With this patch, the example above (which simulates a similar scenario
as in the implementation of this test case) and therefore also the test
suite run successfully through. Tested by myself.

Cc: Vlad Yasevich <vyasevich@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2013-02-04 13:22:33 -05:00
..
associola.c sctp: Add RCU protection to assoc->transport_addr_list 2012-12-07 14:15:04 -05:00
auth.c sctp: fix bogus if statement in sctp_auth_recv_cid() 2012-08-16 13:36:29 -07:00
bind_addr.c sctp: Make sysctl tunables per net 2012-08-14 23:32:16 -07:00
chunk.c sctp: fix -ENOMEM result with invalid user space pointer in sendto() syscall 2012-11-28 11:11:17 -05:00
command.c [SCTP]: Remove sctp_add_cmd_sf wrapper bloat 2008-03-27 17:54:29 -07:00
debug.c sctp: remove completely unsed EMPTY state 2011-04-20 01:51:03 -07:00
endpointola.c Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial 2012-12-13 12:00:02 -08:00
input.c sctp: fix a typo in prototype of __sctp_rcv_lookup() 2012-10-04 15:53:48 -04:00
inqueue.c sctp: Add support to per-association statistics via a new SCTP_GET_ASSOC_STATS call 2012-12-03 13:32:15 -05:00
ipv6.c sctp: fix CONFIG_SCTP_DBG_MSG=y null pointer dereference in sctp_v6_get_dst() 2012-11-30 12:21:27 -05:00
Kconfig sctp: fix Kconfig bug in default cookie hmac selection 2013-01-07 09:27:06 -08:00
Makefile sctp: implement sctp association probing module 2010-04-30 22:41:09 -04:00
objcnt.c sctp: Make the proc files per network namespace. 2012-08-14 23:29:53 -07:00
output.c sctp: Add support to per-association statistics via a new SCTP_GET_ASSOC_STATS call 2012-12-03 13:32:15 -05:00
outqueue.c sctp: refactor sctp_outq_teardown to insure proper re-initalization 2013-01-17 18:39:56 -05:00
primitive.c sctp: Push struct net down to sctp_chunk_event_lookup 2012-08-14 23:30:37 -07:00
probe.c sctp: jsctp_sf_eat_sack: fix jprobes function signature mismatch 2012-12-15 17:14:39 -08:00
proc.c sctp: Add RCU protection to assoc->transport_addr_list 2012-12-07 14:15:04 -05:00
protocol.c sctp: make sctp_addr_wq_timeout_handler static 2012-12-28 20:32:36 -08:00
sm_make_chunk.c sctp: Add support to per-association statistics via a new SCTP_GET_ASSOC_STATS call 2012-12-03 13:32:15 -05:00
sm_sideeffect.c sctp: Add support to per-association statistics via a new SCTP_GET_ASSOC_STATS call 2012-12-03 13:32:15 -05:00
sm_statefuns.c sctp: set association state to established in dupcook_a handler 2013-01-27 19:32:23 -05:00
sm_statetable.c sctp: Make sysctl tunables per net 2012-08-14 23:32:16 -07:00
socket.c sctp: Add support to per-association statistics via a new SCTP_GET_ASSOC_STATS call 2012-12-03 13:32:15 -05:00
ssnmap.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
sysctl.c SCTP: Free the per-net sysctl table on net exit. v2 2013-01-28 00:09:32 -05:00
transport.c sctp: sctp_close: fix release of bindings for deferred call_rcu's 2013-02-04 13:22:33 -05:00
tsnmap.c sctp: use bitmap_weight 2012-11-17 22:01:18 -05:00
ulpevent.c netvm: prevent a stream-specific deadlock 2012-07-31 18:42:47 -07:00
ulpqueue.c sctp: Clean up type-punning in sctp_cmd_t union 2012-11-03 14:54:55 -04:00