summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Gortmaker <paul.gortmaker@windriver.com>2013-01-08 12:26:06 -0500
committerPaul Gortmaker <paul.gortmaker@windriver.com>2013-01-08 15:03:07 -0500
commit9a83f0046d1c7affd6d80688568cb47de1b5dd81 (patch)
treeced86bddb81be6591fbb43f358a08a670e9b9794
parent4229244bcf131b93e3e1d3a156d471a68990dc9d (diff)
downloadlongterm-queue-2.6.34-9a83f0046d1c7affd6d80688568cb47de1b5dd81.tar.gz
add several SCTP fixes
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
-rw-r--r--queue/SCTP-fix-race-between-sctp_bind_addr_free-and-sctp_b.patch78
-rw-r--r--queue/sctp-ABORT-if-receive-reassmbly-or-reodering-queue-i.patch119
-rw-r--r--queue/sctp-Enforce-retransmission-limit-during-shutdown.patch220
-rw-r--r--queue/sctp-Fix-list-corruption-resulting-from-freeing-an-a.patch184
-rw-r--r--queue/sctp-malloc-enough-room-for-asconf-ack-chunk.patch95
-rw-r--r--queue/series5
6 files changed, 701 insertions, 0 deletions
diff --git a/queue/SCTP-fix-race-between-sctp_bind_addr_free-and-sctp_b.patch b/queue/SCTP-fix-race-between-sctp_bind_addr_free-and-sctp_b.patch
new file mode 100644
index 0000000..93c399b
--- /dev/null
+++ b/queue/SCTP-fix-race-between-sctp_bind_addr_free-and-sctp_b.patch
@@ -0,0 +1,78 @@
+From f36966de79399fc7989b285469cc3fdbba55a88f Mon Sep 17 00:00:00 2001
+From: Jacek Luczak <difrost.kernel@gmail.com>
+Date: Thu, 19 May 2011 09:55:13 +0000
+Subject: [PATCH] SCTP: fix race between sctp_bind_addr_free() and
+ sctp_bind_addr_conflict()
+
+commit c182f90bc1f22ce5039b8722e45621d5f96862c2 upstream.
+
+During the sctp_close() call, we do not use rcu primitives to
+destroy the address list attached to the endpoint. At the same
+time, we do the removal of addresses from this list before
+attempting to remove the socket from the port hash
+
+As a result, it is possible for another process to find the socket
+in the port hash that is in the process of being closed. It then
+proceeds to traverse the address list to find the conflict, only
+to have that address list suddenly disappear without rcu() critical
+section.
+
+Fix issue by closing address list removal inside RCU critical
+section.
+
+Race can result in a kernel crash with general protection fault or
+kernel NULL pointer dereference:
+
+kernel: general protection fault: 0000 [#1] SMP
+kernel: RIP: 0010:[<ffffffffa02f3dde>] [<ffffffffa02f3dde>] sctp_bind_addr_conflict+0x64/0x82 [sctp]
+kernel: Call Trace:
+kernel: [<ffffffffa02f415f>] ? sctp_get_port_local+0x17b/0x2a3 [sctp]
+kernel: [<ffffffffa02f3d45>] ? sctp_bind_addr_match+0x33/0x68 [sctp]
+kernel: [<ffffffffa02f4416>] ? sctp_do_bind+0xd3/0x141 [sctp]
+kernel: [<ffffffffa02f5030>] ? sctp_bindx_add+0x4d/0x8e [sctp]
+kernel: [<ffffffffa02f5183>] ? sctp_setsockopt_bindx+0x112/0x4a4 [sctp]
+kernel: [<ffffffff81089e82>] ? generic_file_aio_write+0x7f/0x9b
+kernel: [<ffffffffa02f763e>] ? sctp_setsockopt+0x14f/0xfee [sctp]
+kernel: [<ffffffff810c11fb>] ? do_sync_write+0xab/0xeb
+kernel: [<ffffffff810e82ab>] ? fsnotify+0x239/0x282
+kernel: [<ffffffff810c2462>] ? alloc_file+0x18/0xb1
+kernel: [<ffffffff8134a0b1>] ? compat_sys_setsockopt+0x1a5/0x1d9
+kernel: [<ffffffff8134aaf1>] ? compat_sys_socketcall+0x143/0x1a4
+kernel: [<ffffffff810467dc>] ? sysenter_dispatch+0x7/0x32
+
+Signed-off-by: Jacek Luczak <luczak.jacek@gmail.com>
+Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+CC: Eric Dumazet <eric.dumazet@gmail.com>
+Reviewed-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+---
+ net/sctp/bind_addr.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
+index faf71d1..6150ac5 100644
+--- a/net/sctp/bind_addr.c
++++ b/net/sctp/bind_addr.c
+@@ -140,14 +140,12 @@ void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
+ /* Dispose of the address list. */
+ static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
+ {
+- struct sctp_sockaddr_entry *addr;
+- struct list_head *pos, *temp;
++ struct sctp_sockaddr_entry *addr, *temp;
+
+ /* Empty the bind address list. */
+- list_for_each_safe(pos, temp, &bp->address_list) {
+- addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+- list_del(pos);
+- kfree(addr);
++ list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
++ list_del_rcu(&addr->list);
++ call_rcu(&addr->rcu, sctp_local_addr_free);
+ SCTP_DBG_OBJCNT_DEC(addr);
+ }
+ }
+--
+1.7.12.1
+
diff --git a/queue/sctp-ABORT-if-receive-reassmbly-or-reodering-queue-i.patch b/queue/sctp-ABORT-if-receive-reassmbly-or-reodering-queue-i.patch
new file mode 100644
index 0000000..499cd97
--- /dev/null
+++ b/queue/sctp-ABORT-if-receive-reassmbly-or-reodering-queue-i.patch
@@ -0,0 +1,119 @@
+From 32899f12c58b85ebbfd7c9a014e403c80560e73e Mon Sep 17 00:00:00 2001
+From: Thomas Graf <tgraf@infradead.org>
+Date: Fri, 8 Jul 2011 04:37:46 +0000
+Subject: [PATCH] sctp: ABORT if receive, reassmbly, or reodering queue is not
+ empty while closing socket
+
+commit cd4fcc704f30f2064ab30b5300d44d431e46db50 upstream.
+
+Trigger user ABORT if application closes a socket which has data
+queued on the socket receive queue or chunks waiting on the
+reassembly or ordering queue as this would imply data being lost
+which defeats the point of a graceful shutdown.
+
+This behavior is already practiced in TCP.
+
+We do not check the input queue because that would mean to parse
+all chunks on it to look for unacknowledged data which seems too
+much of an effort. Control chunks or duplicated chunks may also
+be in the input queue and should not be stopping a graceful
+shutdown.
+
+Signed-off-by: Thomas Graf <tgraf@infradead.org>
+Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+---
+ include/net/sctp/ulpevent.h | 2 +-
+ net/sctp/socket.c | 13 ++++++++-----
+ net/sctp/ulpevent.c | 16 +++++++++++++---
+ 3 files changed, 22 insertions(+), 9 deletions(-)
+
+diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
+index 7ea12e8..b93b719 100644
+--- a/include/net/sctp/ulpevent.h
++++ b/include/net/sctp/ulpevent.h
+@@ -80,7 +80,7 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb)
+
+ void sctp_ulpevent_free(struct sctp_ulpevent *);
+ int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
+-void sctp_queue_purge_ulpevents(struct sk_buff_head *list);
++unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list);
+
+ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
+ const struct sctp_association *asoc,
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index 22631c1..03daceb 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -1373,6 +1373,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
+ struct sctp_endpoint *ep;
+ struct sctp_association *asoc;
+ struct list_head *pos, *temp;
++ unsigned int data_was_unread;
+
+ SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
+
+@@ -1382,6 +1383,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
+
+ ep = sctp_sk(sk)->ep;
+
++ /* Clean up any skbs sitting on the receive queue. */
++ data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
++ data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
++
+ /* Walk all associations on an endpoint. */
+ list_for_each_safe(pos, temp, &ep->asocs) {
+ asoc = list_entry(pos, struct sctp_association, asocs);
+@@ -1399,7 +1404,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
+ }
+ }
+
+- if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
++ if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) ||
++ !skb_queue_empty(&asoc->ulpq.reasm) ||
++ (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) {
+ struct sctp_chunk *chunk;
+
+ chunk = sctp_make_abort_user(asoc, NULL, 0);
+@@ -1409,10 +1416,6 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
+ sctp_primitive_SHUTDOWN(asoc, NULL);
+ }
+
+- /* Clean up any skbs sitting on the receive queue. */
+- sctp_queue_purge_ulpevents(&sk->sk_receive_queue);
+- sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby);
+-
+ /* On a TCP-style socket, block for at most linger_time if set. */
+ if (sctp_style(sk, TCP) && timeout)
+ sctp_wait_for_close(sk, timeout);
+diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
+index aa72e89..3b81c62 100644
+--- a/net/sctp/ulpevent.c
++++ b/net/sctp/ulpevent.c
+@@ -1053,9 +1053,19 @@ void sctp_ulpevent_free(struct sctp_ulpevent *event)
+ }
+
+ /* Purge the skb lists holding ulpevents. */
+-void sctp_queue_purge_ulpevents(struct sk_buff_head *list)
++unsigned int sctp_queue_purge_ulpevents(struct sk_buff_head *list)
+ {
+ struct sk_buff *skb;
+- while ((skb = skb_dequeue(list)) != NULL)
+- sctp_ulpevent_free(sctp_skb2event(skb));
++ unsigned int data_unread = 0;
++
++ while ((skb = skb_dequeue(list)) != NULL) {
++ struct sctp_ulpevent *event = sctp_skb2event(skb);
++
++ if (!sctp_ulpevent_is_notification(event))
++ data_unread += skb->len;
++
++ sctp_ulpevent_free(event);
++ }
++
++ return data_unread;
+ }
+--
+1.7.12.1
+
diff --git a/queue/sctp-Enforce-retransmission-limit-during-shutdown.patch b/queue/sctp-Enforce-retransmission-limit-during-shutdown.patch
new file mode 100644
index 0000000..507ef15
--- /dev/null
+++ b/queue/sctp-Enforce-retransmission-limit-during-shutdown.patch
@@ -0,0 +1,220 @@
+From 7a9cc36599317cb0ce372d59d34adba3a19254be Mon Sep 17 00:00:00 2001
+From: Thomas Graf <tgraf@infradead.org>
+Date: Thu, 7 Jul 2011 00:28:35 +0000
+Subject: [PATCH] sctp: Enforce retransmission limit during shutdown
+
+commit f8d9605243280f1870dd2c6c37a735b925c15f3c upstream.
+
+When initiating a graceful shutdown while having data chunks
+on the retransmission queue with a peer which is in zero
+window mode the shutdown is never completed because the
+retransmission error count is reset periodically by the
+following two rules:
+
+ - Do not timeout association while doing zero window probe.
+ - Reset overall error count when a heartbeat request has
+ been acknowledged.
+
+The graceful shutdown will wait for all outstanding TSN to
+be acknowledged before sending the SHUTDOWN request. This
+never happens due to the peer's zero window not acknowledging
+the continuously retransmitted data chunks. Although the
+error counter is incremented for each failed retransmission,
+the receiving of the SACK announcing the zero window clears
+the error count again immediately. Also heartbeat requests
+continue to be sent periodically. The peer acknowledges these
+requests causing the error counter to be reset as well.
+
+This patch changes behaviour to only reset the overall error
+counter for the above rules while not in shutdown. After
+reaching the maximum number of retransmission attempts, the
+T5 shutdown guard timer is scheduled to give the receiver
+some additional time to recover. The timer is stopped as soon
+as the receiver acknowledges any data.
+
+The issue can be easily reproduced by establishing a sctp
+association over the loopback device, constantly queueing
+data at the sender while not reading any at the receiver.
+Wait for the window to reach zero, then initiate a shutdown
+by killing both processes simultaneously. The association
+will never be freed and the chunks on the retransmission
+queue will be retransmitted indefinitely.
+
+Signed-off-by: Thomas Graf <tgraf@infradead.org>
+Acked-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+---
+ include/net/sctp/command.h | 1 +
+ net/sctp/outqueue.c | 20 +++++++++++++++++++-
+ net/sctp/sm_sideeffect.c | 20 ++++++++++++++++++--
+ net/sctp/sm_statefuns.c | 32 +++++++++++++++++++++++---------
+ net/sctp/sm_statetable.c | 2 +-
+ 5 files changed, 62 insertions(+), 13 deletions(-)
+
+diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
+index 2c55a7e..d4699d8 100644
+--- a/include/net/sctp/command.h
++++ b/include/net/sctp/command.h
+@@ -63,6 +63,7 @@ typedef enum {
+ SCTP_CMD_ECN_ECNE, /* Do delayed ECNE processing. */
+ SCTP_CMD_ECN_CWR, /* Do delayed CWR processing. */
+ SCTP_CMD_TIMER_START, /* Start a timer. */
++ SCTP_CMD_TIMER_START_ONCE, /* Start a timer once */
+ SCTP_CMD_TIMER_RESTART, /* Restart a timer. */
+ SCTP_CMD_TIMER_STOP, /* Stop a timer. */
+ SCTP_CMD_INIT_CHOOSE_TRANSPORT, /* Choose transport for an INIT. */
+diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
+index abfc0b8..54e20e3 100644
+--- a/net/sctp/outqueue.c
++++ b/net/sctp/outqueue.c
+@@ -1587,6 +1587,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
+ #endif /* SCTP_DEBUG */
+ if (transport) {
+ if (bytes_acked) {
++ struct sctp_association *asoc = transport->asoc;
++
+ /* We may have counted DATA that was migrated
+ * to this transport due to DEL-IP operation.
+ * Subtract those bytes, since the were never
+@@ -1605,6 +1607,17 @@ static void sctp_check_transmitted(struct sctp_outq *q,
+ transport->error_count = 0;
+ transport->asoc->overall_error_count = 0;
+
++ /*
++ * While in SHUTDOWN PENDING, we may have started
++ * the T5 shutdown guard timer after reaching the
++ * retransmission limit. Stop that timer as soon
++ * as the receiver acknowledged any data.
++ */
++ if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING &&
++ del_timer(&asoc->timers
++ [SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]))
++ sctp_association_put(asoc);
++
+ /* Mark the destination transport address as
+ * active if it is not so marked.
+ */
+@@ -1634,10 +1647,15 @@ static void sctp_check_transmitted(struct sctp_outq *q,
+ * A sender is doing zero window probing when the
+ * receiver's advertised window is zero, and there is
+ * only one data chunk in flight to the receiver.
++ *
++ * Allow the association to timeout while in SHUTDOWN
++ * PENDING or SHUTDOWN RECEIVED in case the receiver
++ * stays in zero window mode forever.
+ */
+ if (!q->asoc->peer.rwnd &&
+ !list_empty(&tlist) &&
+- (sack_ctsn+2 == q->asoc->next_tsn)) {
++ (sack_ctsn+2 == q->asoc->next_tsn) &&
++ q->asoc->state < SCTP_STATE_SHUTDOWN_PENDING) {
+ SCTP_DEBUG_PRINTK("%s: SACK received for zero "
+ "window probe: %u\n",
+ __func__, sack_ctsn);
+diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
+index eb1f42f..c4cb6b8 100644
+--- a/net/sctp/sm_sideeffect.c
++++ b/net/sctp/sm_sideeffect.c
+@@ -669,10 +669,19 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
+ /* 8.3 Upon the receipt of the HEARTBEAT ACK, the sender of the
+ * HEARTBEAT should clear the error counter of the destination
+ * transport address to which the HEARTBEAT was sent.
+- * The association's overall error count is also cleared.
+ */
+ t->error_count = 0;
+- t->asoc->overall_error_count = 0;
++
++ /*
++ * Although RFC4960 specifies that the overall error count must
++ * be cleared when a HEARTBEAT ACK is received, we make an
++ * exception while in SHUTDOWN PENDING. If the peer keeps its
++ * window shut forever, we may never be able to transmit our
++ * outstanding data and rely on the retransmission limit be reached
++ * to shutdown the association.
++ */
++ if (t->asoc->state != SCTP_STATE_SHUTDOWN_PENDING)
++ t->asoc->overall_error_count = 0;
+
+ /* Clear the hb_sent flag to signal that we had a good
+ * acknowledgement.
+@@ -1445,6 +1454,13 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
+ sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr);
+ break;
+
++ case SCTP_CMD_TIMER_START_ONCE:
++ timer = &asoc->timers[cmd->obj.to];
++
++ if (timer_pending(timer))
++ break;
++ /* fall through */
++
+ case SCTP_CMD_TIMER_START:
+ timer = &asoc->timers[cmd->obj.to];
+ timeout = asoc->timeouts[cmd->obj.to];
+diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
+index 24b2cd5..bbfb644 100644
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -5099,7 +5099,7 @@ sctp_disposition_t sctp_sf_do_9_2_start_shutdown(
+ * The sender of the SHUTDOWN MAY also start an overall guard timer
+ * 'T5-shutdown-guard' to bound the overall time for shutdown sequence.
+ */
+- sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
++ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
+ SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
+
+ if (asoc->autoclose)
+@@ -5244,14 +5244,28 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
+ SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS);
+
+ if (asoc->overall_error_count >= asoc->max_retrans) {
+- sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
+- SCTP_ERROR(ETIMEDOUT));
+- /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
+- sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
+- SCTP_PERR(SCTP_ERROR_NO_ERROR));
+- SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+- SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+- return SCTP_DISPOSITION_DELETE_TCB;
++ if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) {
++ /*
++ * We are here likely because the receiver had its rwnd
++ * closed for a while and we have not been able to
++ * transmit the locally queued data within the maximum
++ * retransmission attempts limit. Start the T5
++ * shutdown guard timer to give the receiver one last
++ * chance and some additional time to recover before
++ * aborting.
++ */
++ sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START_ONCE,
++ SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
++ } else {
++ sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
++ SCTP_ERROR(ETIMEDOUT));
++ /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
++ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
++ SCTP_PERR(SCTP_ERROR_NO_ERROR));
++ SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
++ SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
++ return SCTP_DISPOSITION_DELETE_TCB;
++ }
+ }
+
+ /* E1) For the destination address for which the timer
+diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
+index 6d9b3aa..d41d527 100644
+--- a/net/sctp/sm_statetable.c
++++ b/net/sctp/sm_statetable.c
+@@ -897,7 +897,7 @@ static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_
+ /* SCTP_STATE_ESTABLISHED */ \
+ TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
+ /* SCTP_STATE_SHUTDOWN_PENDING */ \
+- TYPE_SCTP_FUNC(sctp_sf_timer_ignore), \
++ TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \
+ /* SCTP_STATE_SHUTDOWN_SENT */ \
+ TYPE_SCTP_FUNC(sctp_sf_t5_timer_expire), \
+ /* SCTP_STATE_SHUTDOWN_RECEIVED */ \
+--
+1.7.12.1
+
diff --git a/queue/sctp-Fix-list-corruption-resulting-from-freeing-an-a.patch b/queue/sctp-Fix-list-corruption-resulting-from-freeing-an-a.patch
new file mode 100644
index 0000000..d4678a0
--- /dev/null
+++ b/queue/sctp-Fix-list-corruption-resulting-from-freeing-an-a.patch
@@ -0,0 +1,184 @@
+From 2271f80407abce6051166fe8aba2cb76fca2a863 Mon Sep 17 00:00:00 2001
+From: Neil Horman <nhorman@tuxdriver.com>
+Date: Mon, 16 Jul 2012 09:13:51 +0000
+Subject: [PATCH] sctp: Fix list corruption resulting from freeing an
+ association on a list
+
+commit 2eebc1e188e9e45886ee00662519849339884d6d upstream.
+
+A few days ago Dave Jones reported this oops:
+
+[22766.294255] general protection fault: 0000 [#1] PREEMPT SMP
+[22766.295376] CPU 0
+[22766.295384] Modules linked in:
+[22766.387137] ffffffffa169f292 6b6b6b6b6b6b6b6b ffff880147c03a90
+ffff880147c03a74
+[22766.387135] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 00000000000
+[22766.387136] Process trinity-watchdo (pid: 10896, threadinfo ffff88013e7d2000,
+[22766.387137] Stack:
+[22766.387140] ffff880147c03a10
+[22766.387140] ffffffffa169f2b6
+[22766.387140] ffff88013ed95728
+[22766.387143] 0000000000000002
+[22766.387143] 0000000000000000
+[22766.387143] ffff880003fad062
+[22766.387144] ffff88013c120000
+[22766.387144]
+[22766.387145] Call Trace:
+[22766.387145] <IRQ>
+[22766.387150] [<ffffffffa169f292>] ? __sctp_lookup_association+0x62/0xd0
+[sctp]
+[22766.387154] [<ffffffffa169f2b6>] __sctp_lookup_association+0x86/0xd0 [sctp]
+[22766.387157] [<ffffffffa169f597>] sctp_rcv+0x207/0xbb0 [sctp]
+[22766.387161] [<ffffffff810d4da8>] ? trace_hardirqs_off_caller+0x28/0xd0
+[22766.387163] [<ffffffff815827e3>] ? nf_hook_slow+0x133/0x210
+[22766.387166] [<ffffffff815902fc>] ? ip_local_deliver_finish+0x4c/0x4c0
+[22766.387168] [<ffffffff8159043d>] ip_local_deliver_finish+0x18d/0x4c0
+[22766.387169] [<ffffffff815902fc>] ? ip_local_deliver_finish+0x4c/0x4c0
+[22766.387171] [<ffffffff81590a07>] ip_local_deliver+0x47/0x80
+[22766.387172] [<ffffffff8158fd80>] ip_rcv_finish+0x150/0x680
+[22766.387174] [<ffffffff81590c54>] ip_rcv+0x214/0x320
+[22766.387176] [<ffffffff81558c07>] __netif_receive_skb+0x7b7/0x910
+[22766.387178] [<ffffffff8155856c>] ? __netif_receive_skb+0x11c/0x910
+[22766.387180] [<ffffffff810d423e>] ? put_lock_stats.isra.25+0xe/0x40
+[22766.387182] [<ffffffff81558f83>] netif_receive_skb+0x23/0x1f0
+[22766.387183] [<ffffffff815596a9>] ? dev_gro_receive+0x139/0x440
+[22766.387185] [<ffffffff81559280>] napi_skb_finish+0x70/0xa0
+[22766.387187] [<ffffffff81559cb5>] napi_gro_receive+0xf5/0x130
+[22766.387218] [<ffffffffa01c4679>] e1000_receive_skb+0x59/0x70 [e1000e]
+[22766.387242] [<ffffffffa01c5aab>] e1000_clean_rx_irq+0x28b/0x460 [e1000e]
+[22766.387266] [<ffffffffa01c9c18>] e1000e_poll+0x78/0x430 [e1000e]
+[22766.387268] [<ffffffff81559fea>] net_rx_action+0x1aa/0x3d0
+[22766.387270] [<ffffffff810a495f>] ? account_system_vtime+0x10f/0x130
+[22766.387273] [<ffffffff810734d0>] __do_softirq+0xe0/0x420
+[22766.387275] [<ffffffff8169826c>] call_softirq+0x1c/0x30
+[22766.387278] [<ffffffff8101db15>] do_softirq+0xd5/0x110
+[22766.387279] [<ffffffff81073bc5>] irq_exit+0xd5/0xe0
+[22766.387281] [<ffffffff81698b03>] do_IRQ+0x63/0xd0
+[22766.387283] [<ffffffff8168ee2f>] common_interrupt+0x6f/0x6f
+[22766.387283] <EOI>
+[22766.387284]
+[22766.387285] [<ffffffff8168eed9>] ? retint_swapgs+0x13/0x1b
+[22766.387285] Code: c0 90 5d c3 66 0f 1f 44 00 00 4c 89 c8 5d c3 0f 1f 00 55 48
+89 e5 48 83
+ec 20 48 89 5d e8 4c 89 65 f0 4c 89 6d f8 66 66 66 66 90 <0f> b7 87 98 00 00 00
+48 89 fb
+49 89 f5 66 c1 c0 08 66 39 46 02
+[22766.387307]
+[22766.387307] RIP
+[22766.387311] [<ffffffffa168a2c9>] sctp_assoc_is_match+0x19/0x90 [sctp]
+[22766.387311] RSP <ffff880147c039b0>
+[22766.387142] ffffffffa16ab120
+[22766.599537] ---[ end trace 3f6dae82e37b17f5 ]---
+[22766.601221] Kernel panic - not syncing: Fatal exception in interrupt
+
+It appears from his analysis and some staring at the code that this is likely
+occuring because an association is getting freed while still on the
+sctp_assoc_hashtable. As a result, we get a gpf when traversing the hashtable
+while a freed node corrupts part of the list.
+
+Nominally I would think that an mibalanced refcount was responsible for this,
+but I can't seem to find any obvious imbalance. What I did note however was
+that the two places where we create an association using
+sctp_primitive_ASSOCIATE (__sctp_connect and sctp_sendmsg), have failure paths
+which free a newly created association after calling sctp_primitive_ASSOCIATE.
+sctp_primitive_ASSOCIATE brings us into the sctp_sf_do_prm_asoc path, which
+issues a SCTP_CMD_NEW_ASOC side effect, which in turn adds a new association to
+the aforementioned hash table. the sctp command interpreter that process side
+effects has not way to unwind previously processed commands, so freeing the
+association from the __sctp_connect or sctp_sendmsg error path would lead to a
+freed association remaining on this hash table.
+
+I've fixed this but modifying sctp_[un]hash_established to use hlist_del_init,
+which allows us to proerly use hlist_unhashed to check if the node is on a
+hashlist safely during a delete. That in turn alows us to safely call
+sctp_unhash_established in the __sctp_connect and sctp_sendmsg error paths
+before freeing them, regardles of what the associations state is on the hash
+list.
+
+I noted, while I was doing this, that the __sctp_unhash_endpoint was using
+hlist_unhsashed in a simmilar fashion, but never nullified any removed nodes
+pointers to make that function work properly, so I fixed that up in a simmilar
+fashion.
+
+I attempted to test this using a virtual guest running the SCTP_RR test from
+netperf in a loop while running the trinity fuzzer, both in a loop. I wasn't
+able to recreate the problem prior to this fix, nor was I able to trigger the
+failure after (neither of which I suppose is suprising). Given the trace above
+however, I think its likely that this is what we hit.
+
+Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
+Reported-by: davej@redhat.com
+CC: davej@redhat.com
+CC: "David S. Miller" <davem@davemloft.net>
+CC: Vlad Yasevich <vyasevich@gmail.com>
+CC: Sridhar Samudrala <sri@us.ibm.com>
+CC: linux-sctp@vger.kernel.org
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+
+diff --git a/net/sctp/input.c b/net/sctp/input.c
+index ea21924..3ad935e 100644
+--- a/net/sctp/input.c
++++ b/net/sctp/input.c
+@@ -752,15 +752,12 @@ static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
+
+ epb = &ep->base;
+
+- if (hlist_unhashed(&epb->node))
+- return;
+-
+ epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
+
+ head = &sctp_ep_hashtable[epb->hashent];
+
+ sctp_write_lock(&head->lock);
+- __hlist_del(&epb->node);
++ hlist_del_init(&epb->node);
+ sctp_write_unlock(&head->lock);
+ }
+
+@@ -841,7 +838,7 @@ static void __sctp_unhash_established(struct sctp_association *asoc)
+ head = &sctp_assoc_hashtable[epb->hashent];
+
+ sctp_write_lock(&head->lock);
+- __hlist_del(&epb->node);
++ hlist_del_init(&epb->node);
+ sctp_write_unlock(&head->lock);
+ }
+
+diff --git a/net/sctp/socket.c b/net/sctp/socket.c
+index 8375609..22631c1 100644
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -1143,8 +1143,14 @@ out_free:
+ SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p"
+ " kaddrs: %p err: %d\n",
+ asoc, kaddrs, err);
+- if (asoc)
++ if (asoc) {
++ /* sctp_primitive_ASSOCIATE may have added this association
++ * To the hash table, try to unhash it, just in case, its a noop
++ * if it wasn't hashed so we're safe
++ */
++ sctp_unhash_established(asoc);
+ sctp_association_free(asoc);
++ }
+ return err;
+ }
+
+@@ -1852,8 +1858,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
+ goto out_unlock;
+
+ out_free:
+- if (new_asoc)
++ if (new_asoc) {
++ sctp_unhash_established(asoc);
+ sctp_association_free(asoc);
++ }
+ out_unlock:
+ sctp_release_sock(sk);
+
+--
+1.7.12.1
+
diff --git a/queue/sctp-malloc-enough-room-for-asconf-ack-chunk.patch b/queue/sctp-malloc-enough-room-for-asconf-ack-chunk.patch
new file mode 100644
index 0000000..6bc6f78
--- /dev/null
+++ b/queue/sctp-malloc-enough-room-for-asconf-ack-chunk.patch
@@ -0,0 +1,95 @@
+From e8be14a4e81f2c58f599f18ccbfbd91dd8dc7150 Mon Sep 17 00:00:00 2001
+From: Wei Yongjun <yjwei@cn.fujitsu.com>
+Date: Thu, 31 Mar 2011 23:42:55 +0000
+Subject: [PATCH] sctp: malloc enough room for asconf-ack chunk
+
+commit 2cab86bee8e7f353e6ac8c15b3eb906643497644 upstream.
+
+Sometime the ASCONF_ACK parameters can equal to the fourfold of
+ASCONF parameters, this only happend in some special case:
+
+ ASCONF parameter is :
+ Unrecognized Parameter (4 bytes)
+ ASCONF_ACK parameter should be:
+ Error Cause Indication parameter (8 bytes header)
+ + Error Cause (4 bytes header)
+ + Unrecognized Parameter (4bytes)
+
+Four 4bytes Unrecognized Parameters in ASCONF chunk will cause panic.
+
+Pid: 0, comm: swapper Not tainted 2.6.38-next+ #22 Bochs Bochs
+EIP: 0060:[<c0717eae>] EFLAGS: 00010246 CPU: 0
+EIP is at skb_put+0x60/0x70
+EAX: 00000077 EBX: c09060e2 ECX: dec1dc30 EDX: c09469c0
+ESI: 00000000 EDI: de3c8d40 EBP: dec1dc58 ESP: dec1dc2c
+ DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
+Process swapper (pid: 0, ti=dec1c000 task=c09aef20 task.ti=c0980000)
+Stack:
+ c09469c0 e1894fa4 00000044 00000004 de3c8d00 de3c8d00 de3c8d44 de3c8d40
+ c09060e2 de25dd80 de3c8d40 dec1dc7c e1894fa4 dec1dcb0 00000040 00000004
+ 00000000 00000800 00000004 00000004 dec1dce0 e1895a2b dec1dcb4 de25d960
+Call Trace:
+ [<e1894fa4>] ? sctp_addto_chunk+0x4e/0x89 [sctp]
+ [<e1894fa4>] sctp_addto_chunk+0x4e/0x89 [sctp]
+ [<e1895a2b>] sctp_process_asconf+0x32f/0x3d1 [sctp]
+ [<e188d554>] sctp_sf_do_asconf+0xf8/0x173 [sctp]
+ [<e1890b02>] sctp_do_sm+0xb8/0x159 [sctp]
+ [<e18a2248>] ? sctp_cname+0x0/0x52 [sctp]
+ [<e189392d>] sctp_assoc_bh_rcv+0xac/0xe3 [sctp]
+ [<e1897d76>] sctp_inq_push+0x2d/0x30 [sctp]
+ [<e18a21b2>] sctp_rcv+0x7a7/0x83d [sctp]
+ [<c077a95c>] ? ipv4_confirm+0x118/0x125
+ [<c073a970>] ? nf_iterate+0x34/0x62
+ [<c074789d>] ? ip_local_deliver_finish+0x0/0x194
+ [<c074789d>] ? ip_local_deliver_finish+0x0/0x194
+ [<c0747992>] ip_local_deliver_finish+0xf5/0x194
+ [<c074789d>] ? ip_local_deliver_finish+0x0/0x194
+ [<c0747a6e>] NF_HOOK.clone.1+0x3d/0x44
+ [<c0747ab3>] ip_local_deliver+0x3e/0x44
+ [<c074789d>] ? ip_local_deliver_finish+0x0/0x194
+ [<c074775c>] ip_rcv_finish+0x29f/0x2c7
+ [<c07474bd>] ? ip_rcv_finish+0x0/0x2c7
+ [<c0747a6e>] NF_HOOK.clone.1+0x3d/0x44
+ [<c0747cae>] ip_rcv+0x1f5/0x233
+ [<c07474bd>] ? ip_rcv_finish+0x0/0x2c7
+ [<c071dce3>] __netif_receive_skb+0x310/0x336
+ [<c07221f3>] netif_receive_skb+0x4b/0x51
+ [<e0a4ed3d>] cp_rx_poll+0x1e7/0x29c [8139cp]
+ [<c072275e>] net_rx_action+0x65/0x13a
+ [<c0445a54>] __do_softirq+0xa1/0x149
+ [<c04459b3>] ? __do_softirq+0x0/0x149
+ <IRQ>
+ [<c0445891>] ? irq_exit+0x37/0x72
+ [<c040a7e9>] ? do_IRQ+0x81/0x95
+ [<c07b3670>] ? common_interrupt+0x30/0x38
+ [<c0428058>] ? native_safe_halt+0xa/0xc
+ [<c040f5d7>] ? default_idle+0x58/0x92
+ [<c0408fb0>] ? cpu_idle+0x96/0xb2
+ [<c0797989>] ? rest_init+0x5d/0x5f
+ [<c09fd90c>] ? start_kernel+0x34b/0x350
+ [<c09fd0cb>] ? i386_start_kernel+0xba/0xc1
+
+Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
+
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 70d6c10..ad633d9 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3110,10 +3110,10 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
+
+ /* create an ASCONF_ACK chunk.
+ * Based on the definitions of parameters, we know that the size of
+- * ASCONF_ACK parameters are less than or equal to the twice of ASCONF
++ * ASCONF_ACK parameters are less than or equal to the fourfold of ASCONF
+ * parameters.
+ */
+- asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 2);
++ asconf_ack = sctp_make_asconf_ack(asoc, serial, chunk_len * 4);
+ if (!asconf_ack)
+ goto done;
+
+--
+1.7.12.1
+
diff --git a/queue/series b/queue/series
index 4596ff6..141139f 100644
--- a/queue/series
+++ b/queue/series
@@ -64,3 +64,8 @@ USB-cdc-acm-add-IDs-for-Motorola-H24-HSPA-USB-module.patch
#misc
udf-Fortify-loading-of-sparing-table.patch
udf-Avoid-run-away-loop-when-partition-table-length-.patch
+sctp-malloc-enough-room-for-asconf-ack-chunk.patch
+sctp-Fix-list-corruption-resulting-from-freeing-an-a.patch
+sctp-ABORT-if-receive-reassmbly-or-reodering-queue-i.patch
+sctp-Enforce-retransmission-limit-during-shutdown.patch
+SCTP-fix-race-between-sctp_bind_addr_free-and-sctp_b.patch