From mboxrd@z Thu Jan 1 00:00:00 1970 From: Wei Yongjun Subject: [PATCH] SCTP: Fix kernel panic while received retransmitted ASCONF chunk 3 times Date: Sun, 27 Jan 2008 01:09:20 +0900 Message-ID: <479B5B30.4020308@cn.fujitsu.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: Vlad Yasevich To: lksctp-developers@lists.sourceforge.net, netdev@vger.kernel.org Return-path: Received: from cn.fujitsu.com ([222.73.24.84]:51032 "EHLO song.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-OK) by vger.kernel.org with ESMTP id S1760942AbYAZQKE (ORCPT ); Sat, 26 Jan 2008 11:10:04 -0500 Sender: netdev-owner@vger.kernel.org List-ID: While endpoint recived the ASCONF chunk with the same serial number for 3 times, the endpoint will panic. Test as following: Endpoint A Endpoint B (ESTABLISHED) (ESTABLISHED) ASCONF ----------> (serial = 1) <---------- ASCONF-ACK ASCONF ----------> (serial = 1) <---------- ASCONF-ACK ASCONF ----------> (serial = 1) kernel panic This is besause if endpoint received the first ASCONF chunk, ASCONF-ACK chunk will be send to reponse this ASCONF chunk, and the ASCONF-ACK will be cached as asoc->addip_last_asconf_ack. After this, if ASCONF chunk with the same serial number received will be treat as retransmitted ASCONF chunk and just responsed with the cached asoc->addip_last_asconf_ack. But before we use this cached chunk, we not increase the user count of this chunk with sctp_chunk_hold() , after send ASCONF-ACK, sctp_chunk_free() will be used to free asoc->addip_last_asconf_ack. So when the third ASCONF chunk with the same serial number is received, it responsed with the cached asoc->addip_last_asconf_ack too, but asoc->addip_last_asconf_ack has been freed, So kernel panic is occurred. Folowing is the kernel panic message. And this patch fix this problem. kernel BUG at net/sctp/outqueue.c:789! invalid opcode: 0000 [#1] SMP Modules linked in: md5 sctp ipv6 dm_mirror dm_mod sbs sbshc battery lp snd_ens1371 Pid: 0, comm: swapper Not tainted (2.6.24 #1) EIP: 0060:[] EFLAGS: 00010216 CPU: 0 EIP is at sctp_outq_flush+0x16b/0x5d3 [sctp] EAX: c735f43c EBX: c8a9dc64 ECX: 00000046 EDX: 00000000 ESI: c7aa3b00 EDI: c794ea00 EBP: c7a953d0 ESP: c0757cf4 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process swapper (pid: 0, ti=c0757000 task=c06d63a0 task.ti=c070f000) Stack: c1107d80 c0441e6f c7aa3b00 00000064 00000000 c7a953bc c794eae0 c7a94000 034d0be8 00000001 00000000 00000000 00000001 00000000 c043bc66 c7aa3b00 c7a953bc c7a94000 c8a9c760 c042bfc6 c8a9f18d c7aa3b00 c7a953bc c8a90259 Call Trace: [] tick_handle_periodic+0x17/0x5c [] autoremove_wake_function+0x15/0x35 [] printk+0x1b/0x1f [] sctp_outq_tail+0x128/0x172 [sctp] [] sctp_do_sm+0xeb0/0x103f [sctp] [] sctp_assoc_bh_rcv+0xc1/0xf4 [sctp] [] sctp_inq_push+0x2a/0x2d [sctp] [] sctp_rcv+0x5c3/0x6a4 [sctp] [] try_to_wake_up+0x3bb/0x3c5 [] __update_rq_clock+0x19/0x156 [] clocksource_get_next+0x39/0x3f [] __update_rq_clock+0x19/0x156 [] ip_local_deliver_finish+0xda/0x17d [] ip_rcv_finish+0x2c5/0x2e4 [] tick_handle_periodic+0x17/0x5c [] smp_apic_timer_interrupt+0x74/0x80 [] ip_rcv+0x0/0x237 [] netif_receive_skb+0x328/0x392 [] process_backlog+0x5c/0x9a [] net_rx_action+0x8d/0x163 [] run_timer_softirq+0x2f/0x156 [] __do_softirq+0x5d/0xc1 [] do_softirq+0x59/0xa8 [] tick_handle_periodic+0x17/0x5c [] smp_apic_timer_interrupt+0x74/0x80 [] default_idle+0x0/0x3e [] default_idle+0x0/0x3e [] apic_timer_interrupt+0x28/0x30 [] default_idle+0x0/0x3e [] default_idle+0x2c/0x3e [] cpu_idle+0x92/0xab [] start_kernel+0x2f7/0x2ff [] unknown_bootoption+0x0/0x195 ======================= Code: 00 89 f2 89 d8 e8 b3 88 00 00 89 d8 e8 1e 83 00 00 85 c0 89 44 24 2c EIP: [] sctp_outq_flush+0x16b/0x5d3 [sctp] SS:ESP 0068:c0757cf4 Kernel panic - not syncing: Fatal exception in interrupt Signed-off-by: Wei Yongjun --- a/net/sctp/sm_statefuns.c 2008-01-25 00:50:27.000000000 -0500 +++ b/net/sctp/sm_statefuns.c 2008-01-25 03:03:15.000000000 -0500 @@ -3420,9 +3420,10 @@ sctp_disposition_t sctp_sf_do_asconf(con * time and instead of re-processing the ASCONF (with the same * serial number) it may just re-transmit the ASCONF-ACK. */ - if (asoc->addip_last_asconf_ack) + if (asoc->addip_last_asconf_ack) { asconf_ack = asoc->addip_last_asconf_ack; - else + sctp_chunk_hold(asconf_ack); + } else return SCTP_DISPOSITION_DISCARD; } else { /* ADDIP 4.2 C4) Otherwise, the ASCONF Chunk is discarded since