diff options
author | Paul Gortmaker <paul.gortmaker@windriver.com> | 2013-01-08 12:26:06 -0500 |
---|---|---|
committer | Paul Gortmaker <paul.gortmaker@windriver.com> | 2013-01-08 15:03:07 -0500 |
commit | 9a83f0046d1c7affd6d80688568cb47de1b5dd81 (patch) | |
tree | ced86bddb81be6591fbb43f358a08a670e9b9794 | |
parent | 4229244bcf131b93e3e1d3a156d471a68990dc9d (diff) | |
download | longterm-queue-2.6.34-9a83f0046d1c7affd6d80688568cb47de1b5dd81.tar.gz |
add several SCTP fixes
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
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 |