Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sctp: handle association restarts when the socket is closed.

Currently association restarts do not take into consideration the
state of the socket. When a restart happens, the current assocation
simply transitions into established state. This creates a condition
where a remote system, through a the restart procedure, may create a
local association that is no way reachable by user. The conditions
to trigger this are as follows:
1) Remote does not acknoledge some data causing data to remain
outstanding.
2) Local application calls close() on the socket. Since data
is still outstanding, the association is placed in SHUTDOWN_PENDING
state. However, the socket is closed.
3) The remote tries to create a new association, triggering a restart
on the local system. The association moves from SHUTDOWN_PENDING
to ESTABLISHED. At this point, it is no longer reachable by
any socket on the local system.

This patch addresses the above situation by moving the newly ESTABLISHED
association into SHUTDOWN-SENT state and bundling a SHUTDOWN after
the COOKIE-ACK chunk. This way, the restarted associate immidiately
enters the shutdown procedure and forces the termination of the
unreachable association.

Reported-by: David Laight <David.Laight@aculab.com>
Signed-off-by: Vlad Yasevich <vyasevich@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Vlad Yasevich and committed by
David S. Miller
bdf6fa52 f408c3d9

+17 -4
+1 -1
include/net/sctp/command.h
··· 115 115 * analysis of the state functions, but in reality just taken from 116 116 * thin air in the hopes othat we don't trigger a kernel panic. 117 117 */ 118 - #define SCTP_MAX_NUM_COMMANDS 14 118 + #define SCTP_MAX_NUM_COMMANDS 20 119 119 120 120 typedef union { 121 121 void *zero_all; /* Set to NULL to clear the entire union */
+16 -3
net/sctp/sm_statefuns.c
··· 1775 1775 /* Update the content of current association. */ 1776 1776 sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); 1777 1777 sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); 1778 - sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, 1779 - SCTP_STATE(SCTP_STATE_ESTABLISHED)); 1780 - sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); 1778 + if (sctp_state(asoc, SHUTDOWN_PENDING) && 1779 + (sctp_sstate(asoc->base.sk, CLOSING) || 1780 + sock_flag(asoc->base.sk, SOCK_DEAD))) { 1781 + /* if were currently in SHUTDOWN_PENDING, but the socket 1782 + * has been closed by user, don't transition to ESTABLISHED. 1783 + * Instead trigger SHUTDOWN bundled with COOKIE_ACK. 1784 + */ 1785 + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); 1786 + return sctp_sf_do_9_2_start_shutdown(net, ep, asoc, 1787 + SCTP_ST_CHUNK(0), NULL, 1788 + commands); 1789 + } else { 1790 + sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, 1791 + SCTP_STATE(SCTP_STATE_ESTABLISHED)); 1792 + sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl)); 1793 + } 1781 1794 return SCTP_DISPOSITION_CONSUME; 1782 1795 1783 1796 nomem_ev: