Bug 18592
Summary: | Remote/local Denial of Service vulnerability in SCTP packet/chunk handling | ||
---|---|---|---|
Product: | Networking | Reporter: | Thomas Dreibholz (dreibh) |
Component: | Other | Assignee: | Arnaldo Carvalho de Melo (acme) |
Status: | CLOSED CODE_FIX | ||
Severity: | blocking | CC: | alan |
Priority: | P1 | ||
Hardware: | All | ||
OS: | Linux | ||
Kernel Version: | 2.6.36-rc4 | Subsystem: | |
Regression: | No | Bisected commit-id: | |
Attachments: | Patch to fix the problem |
(switched to email. Please respond via emailed reply-to-all, not via the bugzilla web interface). On Wed, 15 Sep 2010 12:17:21 GMT bugzilla-daemon@bugzilla.kernel.org wrote: > https://bugzilla.kernel.org/show_bug.cgi?id=18592 > > Summary: Remote/local Denial of Service vulnerability in SCTP > packet/chunk handling > Product: Networking > Version: 2.5 > Kernel Version: 2.6.36-rc4 > Platform: All > OS/Version: Linux > Tree: Mainline > Status: NEW > Severity: blocking > Priority: P1 > Component: Other > AssignedTo: acme@ghostprotocols.net > ReportedBy: dreibh@iem.uni-due.de > Regression: No > > > Created an attachment (id=30132) > --> (https://bugzilla.kernel.org/attachment.cgi?id=30132) > Patch to fix the problem > > sctp_outq_flush() in net/sctp/outqueue.c may call sctp_packet_reset() on a > packet structure which has already been filled with chunks. > sctp_packet_reset() > will not take care of the chunks in its list and only reset the packet > length. > After that, the SCTP code assumes the packet to be re-initialized and adds > further chunks to the structure. The length will be wrong. When actually > trying to transmit the packet, the packet sk_buff structure may be exceeded > within sctp_packet_transmit(), resulting in skb_over_panic() => denial of > service. > > Such a DoS can be triggered by a malicious remote SCTP instance, as follows: > - The remote endpoint has to use two paths (i.e. 2 IP addresses); easy to > achieve using an IPv4 address and an IPv6 address -> path A and B. > - The remote user has to trigger the transmission of a HEARTBEAT_ACK on path > A. This is trivial, by sending a HEARTBEAT chunk. sctp_outq_flush() will call > sctp_packet_config() for the packet on path A. The HEARTBEAT_ACK will be > added > to this packet. > - The remote user has to trigger a DATA chunk retransmission on path B. This > is trivial, since it only has to send appropriate SACK chunks. > sctp_outq_flush() notices that the retransmission is on a different path and > calls sctp_packet_config() for the packet on path B. The DATA chunk to be > retransmitted is added to this packet. > - The local instance has to send another DATA chunk on path A. This depends > on > the application, but should be easy to trigger from a remote instance. > sctp_outq_flush() notices that the path has changed again, and calls > sctp_packet_config() for the packet on path A. This resets the size of the > HEARTBEAT_ACK chunk, but the chunk remains in the packet. If > size(HEARTBEAT_ACK) + size(DATA) > MTU - overhead, the next call to > sctp_packet_transmit() causes the kernel panic => DoS. > > PID: 13309 TASK: f6636600 CPU: 1 COMMAND: "scriptingclient" > #0 [e4d91968] crash_kexec at c0189fea > #1 [e4d919b4] do_invalid_op at c0104a46 > #2 [e4d91a50] error_code (via invalid_op) at c058d1a1 > EAX: 0000008b EBX: f89e168d ECX: ffffff78 EDX: 00000000 EBP: e4d91ab8 > DS: 007b ESI: f601e000 ES: 007b EDI: e44570e8 GS: 00e0 > CS: 0060 EIP: c04b9d7c ERR: ffffffff EFLAGS: 00010286 > #3 [e4d91a84] skb_over_panic at c04b9d7c > #4 [e4d91a94] sctp_packet_transmit at f89e1688 > #5 [e4d91ac8] sctp_packet_transmit at f89e1688 > #6 [e4d91b14] sctp_packet_transmit_chunk at f89e1d23 > #7 [e4d91b2c] sctp_outq_flush at f89d78f9 > #8 [e4d91ba8] sctp_outq_uncork at f89d7994 > #9 [e4d91bb0] sctp_cmd_interpreter at f89cce71 > #10 [e4d91c00] sctp_side_effects at f89cdbff > #11 [e4d91c30] sctp_do_sm at f89cdd3d > #12 [e4d91cdc] sctp_assoc_bh_rcv at f89d1279 > #13 [e4d91d0c] sctp_inq_push at f89d6773 > #14 [e4d91d14] sctp_rcv at f89e2e5d > #15 [e4d91d8c] ip_local_deliver_finish at c04ec6e5 > #16 [e4d91db0] ip_local_deliver at c04ec93a > #17 [e4d91dcc] ip_rcv_finish at c04ebf98 > #18 [e4d91df4] ip_rcv at c04ec449 > #19 [e4d91e1c] netif_receive_skb at c04c37a4 > #20 [e4d91e58] e1000_receive_skb at f80a45bb > #21 [e4d91e68] e1000_clean_rx_irq at f80a88b6 > #22 [e4d91edc] e1000_clean at f80a799d > #23 [e4d91efc] net_rx_action at c04c410a > #24 [e4d91f28] __do_softirq at c0153132 > #25 [e4d91f70] do_softirq at c0153290 > #26 [e4d91f7c] irq_exit at c01533e0 > #27 [e4d91f84] do_IRQ at c0591240 > #28 [e4d91fb0] common_interrupt at c0103a2b > EAX: 9af6e0c6 EBX: b0dad373 ECX: 00000005 EDX: 4d995cbc > DS: 007b ESI: 598130cd ES: 007b EDI: 00b5dfc0 > SS: 007b ESP: bfca6d80 EBP: bfca6df8 GS: 0033 > CS: 0073 EIP: 0804b816 ERR: ffffff55 EFLAGS: 00000a86 > > In a similar way, the problem can also be triggered by a local user, having > only the permission to establish SCTP associations. Of course, the problem > can > also occur during normal network operation, just by a retransmission at the > wrong time. > > > The attached patch against 2.6.36-rc4 (git repository) fixes > sctp_outq_flush() > by ensuring that the packet on each path is initialized only once. > Furthermore, > a BUG_ON() statement ensures that further problems by calling > sctp_packet_reset() on packets with chunks are detected directly. > Thanks, but please send patches via email, not via bugzilla. Documentation/SubmittingPatches has some tips. Suitable recipients for this patch are, from the MAINTAINERS file: M: Vlad Yasevich <vladislav.yasevich@hp.com> M: Sridhar Samudrala <sri@us.ibm.com> L: linux-sctp@vger.kernel.org but please just send it as a reply-to-all to this email so that everyone knows wht's happening. I'd suggest that you also add the line Cc: <stable@kernel.org> to the end of the changelog so that we don't forget to consider the patch for backporting. diff --git a/net/sctp/output.c b/net/sctp/output.c index a646681..744e667 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -72,6 +72,7 @@ static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet *packet, static void sctp_packet_reset(struct sctp_packet *packet) { + BUG_ON(!list_empty(&packet->chunk_list)); packet->size = packet->overhead; packet->has_cookie_echo = 0; packet->has_sack = 0; diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index c04b2eb..69296c8 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -799,13 +799,13 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) */ if (new_transport != transport) { transport = new_transport; + packet = &transport->packet; if (list_empty(&transport->send_ready)) { list_add_tail(&transport->send_ready, &transport_list); + sctp_packet_config(packet, vtag, + asoc->peer.ecn_capable); } - packet = &transport->packet; - sctp_packet_config(packet, vtag, - asoc->peer.ecn_capable); } switch (chunk->chunk_hdr->type) { @@ -900,15 +900,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) /* Switch transports & prepare the packet. */ transport = asoc->peer.retran_path; + packet = &transport->packet; if (list_empty(&transport->send_ready)) { list_add_tail(&transport->send_ready, &transport_list); + sctp_packet_config(packet, vtag, + asoc->peer.ecn_capable); } - - packet = &transport->packet; - sctp_packet_config(packet, vtag, - asoc->peer.ecn_capable); retran: error = sctp_outq_flush_rtx(q, packet, rtx_timeout, &start_timer); @@ -970,6 +969,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) /* Change packets if necessary. */ if (new_transport != transport) { transport = new_transport; + packet = &transport->packet; /* Schedule to have this transport's * packet flushed. @@ -977,15 +977,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) if (list_empty(&transport->send_ready)) { list_add_tail(&transport->send_ready, &transport_list); - } + sctp_packet_config(packet, vtag, + asoc->peer.ecn_capable); - packet = &transport->packet; - sctp_packet_config(packet, vtag, - asoc->peer.ecn_capable); - /* We've switched transports, so apply the - * Burst limit to the new transport. - */ - sctp_transport_burst_limited(transport); + /* We've switched transports, so apply the + * Burst limit to the new transport. + */ + sctp_transport_burst_limited(transport); + } } SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ", Reply-To: vladislav.yasevich@hp.com On 09/15/2010 03:43 PM, Andrew Morton wrote: > > > Thanks, but please send patches via email, not via bugzilla. > Documentation/SubmittingPatches has some tips. Suitable recipients for > this patch are, from the MAINTAINERS file: > > M: Vlad Yasevich <vladislav.yasevich@hp.com> > M: Sridhar Samudrala <sri@us.ibm.com> > L: linux-sctp@vger.kernel.org > > but please just send it as a reply-to-all to this email so that everyone > knows wht's happening. > > I'd suggest that you also add the line > > Cc: <stable@kernel.org> > > to the end of the changelog so that we don't forget to consider the > patch for backporting. > > Hi Andrew There is a much simpler solution to this problem that I posted to netdev today. -vlad. > > diff --git a/net/sctp/output.c b/net/sctp/output.c > index a646681..744e667 100644 > --- a/net/sctp/output.c > +++ b/net/sctp/output.c > @@ -72,6 +72,7 @@ static sctp_xmit_t sctp_packet_will_fit(struct sctp_packet > *packet, > > static void sctp_packet_reset(struct sctp_packet *packet) > { > + BUG_ON(!list_empty(&packet->chunk_list)); > packet->size = packet->overhead; > packet->has_cookie_echo = 0; > packet->has_sack = 0; > diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c > index c04b2eb..69296c8 100644 > --- a/net/sctp/outqueue.c > +++ b/net/sctp/outqueue.c > @@ -799,13 +799,13 @@ static int sctp_outq_flush(struct sctp_outq *q, int > rtx_timeout) > */ > if (new_transport != transport) { > transport = new_transport; > + packet = &transport->packet; > if (list_empty(&transport->send_ready)) { > list_add_tail(&transport->send_ready, > &transport_list); > + sctp_packet_config(packet, vtag, > + asoc->peer.ecn_capable); > } > - packet = &transport->packet; > - sctp_packet_config(packet, vtag, > - asoc->peer.ecn_capable); > } > > switch (chunk->chunk_hdr->type) { > @@ -900,15 +900,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int > rtx_timeout) > /* Switch transports & prepare the packet. */ > > transport = asoc->peer.retran_path; > + packet = &transport->packet; > > if (list_empty(&transport->send_ready)) { > list_add_tail(&transport->send_ready, > &transport_list); > + sctp_packet_config(packet, vtag, > + asoc->peer.ecn_capable); > } > - > - packet = &transport->packet; > - sctp_packet_config(packet, vtag, > - asoc->peer.ecn_capable); > retran: > error = sctp_outq_flush_rtx(q, packet, > rtx_timeout, &start_timer); > @@ -970,6 +969,7 @@ static int sctp_outq_flush(struct sctp_outq *q, int > rtx_timeout) > /* Change packets if necessary. */ > if (new_transport != transport) { > transport = new_transport; > + packet = &transport->packet; > > /* Schedule to have this transport's > * packet flushed. > @@ -977,15 +977,14 @@ static int sctp_outq_flush(struct sctp_outq *q, int > rtx_timeout) > if (list_empty(&transport->send_ready)) { > list_add_tail(&transport->send_ready, > &transport_list); > - } > + sctp_packet_config(packet, vtag, > + > asoc->peer.ecn_capable); > > - packet = &transport->packet; > - sctp_packet_config(packet, vtag, > - asoc->peer.ecn_capable); > - /* We've switched transports, so apply the > - * Burst limit to the new transport. > - */ > - sctp_transport_burst_limited(transport); > + /* We've switched transports, so apply > the > + * Burst limit to the new transport. > + */ > + > sctp_transport_burst_limited(transport); > + } > } > > SCTP_DEBUG_PRINTK("sctp_outq_flush(%p, %p[%s]), ", > > -- > To unsubscribe from this list: send the line "unsubscribe linux-sctp" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > On Donnerstag 16 September 2010, Vlad Yasevich wrote:
> On 09/15/2010 03:43 PM, Andrew Morton wrote:
> > Thanks, but please send patches via email, not via bugzilla.
> > Documentation/SubmittingPatches has some tips. Suitable recipients for
> > this patch are, from the MAINTAINERS file:
> >
> > M: Vlad Yasevich <vladislav.yasevich@hp.com>
> > M: Sridhar Samudrala <sri@us.ibm.com>
> > L: linux-sctp@vger.kernel.org
> >
> > but please just send it as a reply-to-all to this email so that everyone
> > knows wht's happening.
> >
> > I'd suggest that you also add the line
> >
> > Cc: <stable@kernel.org>
> >
> > to the end of the changelog so that we don't forget to consider the
> > patch for backporting.
>
> Hi Andrew
>
> There is a much simpler solution to this problem that I posted to netdev
> today.
Dear all,
Vlad's patch solves the problem. I hope this patch can go into the mailine
kernel soon, in order to get distribution kernels fixed as soon as possible. It
is relatively easy to trigger the denial of service problem, making all
systems providing SCTP-based services vulnerable to a remote DoS attack.
I have also been able to reproduce the problem with kernel 2.6.32, i.e. at
least all kernels from 2.6.32 to 2.6.36 are affected.
Best regards
On Sat, Sep 18, 2010 at 04:11:03PM +0200, Thomas Dreibholz wrote:
> On Donnerstag 16 September 2010, Vlad Yasevich wrote:
> > On 09/15/2010 03:43 PM, Andrew Morton wrote:
> > > Thanks, but please send patches via email, not via bugzilla.
> > > Documentation/SubmittingPatches has some tips. Suitable recipients for
> > > this patch are, from the MAINTAINERS file:
> > >
> > > M: Vlad Yasevich <vladislav.yasevich@hp.com>
> > > M: Sridhar Samudrala <sri@us.ibm.com>
> > > L: linux-sctp@vger.kernel.org
> > >
> > > but please just send it as a reply-to-all to this email so that everyone
> > > knows wht's happening.
> > >
> > > I'd suggest that you also add the line
> > >
> > > Cc: <stable@kernel.org>
> > >
> > > to the end of the changelog so that we don't forget to consider the
> > > patch for backporting.
> >
> > Hi Andrew
> >
> > There is a much simpler solution to this problem that I posted to netdev
> > today.
>
> Dear all,
>
> Vlad's patch solves the problem. I hope this patch can go into the mailine
> kernel soon, in order to get distribution kernels fixed as soon as possible.
> It
> is relatively easy to trigger the denial of service problem, making all
> systems providing SCTP-based services vulnerable to a remote DoS attack.
>
> I have also been able to reproduce the problem with kernel 2.6.32, i.e. at
> least all kernels from 2.6.32 to 2.6.36 are affected.
Is this in Linus's tree now? If so, does anyone have the git commit id?
thanks,
greg k-h
From: Greg KH <greg@kroah.com> Date: Thu, 23 Sep 2010 11:05:15 -0700 > On Sat, Sep 18, 2010 at 04:11:03PM +0200, Thomas Dreibholz wrote: >> Vlad's patch solves the problem. I hope this patch can go into the mailine >> kernel soon, in order to get distribution kernels fixed as soon as possible. >> It >> is relatively easy to trigger the denial of service problem, making all >> systems providing SCTP-based services vulnerable to a remote DoS attack. >> >> I have also been able to reproduce the problem with kernel 2.6.32, i.e. at >> least all kernels from 2.6.32 to 2.6.36 are affected. > > Is this in Linus's tree now? If so, does anyone have the git commit id? Should be: 4bdab43323b459900578b200a4b8cf9713ac8fab On Thu, Sep 23, 2010 at 12:21:55PM -0700, David Miller wrote:
> From: Greg KH <greg@kroah.com>
> Date: Thu, 23 Sep 2010 11:05:15 -0700
>
> > On Sat, Sep 18, 2010 at 04:11:03PM +0200, Thomas Dreibholz wrote:
> >> Vlad's patch solves the problem. I hope this patch can go into the mailine
> >> kernel soon, in order to get distribution kernels fixed as soon as
> possible. It
> >> is relatively easy to trigger the denial of service problem, making all
> >> systems providing SCTP-based services vulnerable to a remote DoS attack.
> >>
> >> I have also been able to reproduce the problem with kernel 2.6.32, i.e. at
> >> least all kernels from 2.6.32 to 2.6.36 are affected.
> >
> > Is this in Linus's tree now? If so, does anyone have the git commit id?
>
> Should be: 4bdab43323b459900578b200a4b8cf9713ac8fab
Wonderful, now queued up.
thanks,
greg k-h
|
Created attachment 30132 [details] Patch to fix the problem sctp_outq_flush() in net/sctp/outqueue.c may call sctp_packet_reset() on a packet structure which has already been filled with chunks. sctp_packet_reset() will not take care of the chunks in its list and only reset the packet length. After that, the SCTP code assumes the packet to be re-initialized and adds further chunks to the structure. The length will be wrong. When actually trying to transmit the packet, the packet sk_buff structure may be exceeded within sctp_packet_transmit(), resulting in skb_over_panic() => denial of service. Such a DoS can be triggered by a malicious remote SCTP instance, as follows: - The remote endpoint has to use two paths (i.e. 2 IP addresses); easy to achieve using an IPv4 address and an IPv6 address -> path A and B. - The remote user has to trigger the transmission of a HEARTBEAT_ACK on path A. This is trivial, by sending a HEARTBEAT chunk. sctp_outq_flush() will call sctp_packet_config() for the packet on path A. The HEARTBEAT_ACK will be added to this packet. - The remote user has to trigger a DATA chunk retransmission on path B. This is trivial, since it only has to send appropriate SACK chunks. sctp_outq_flush() notices that the retransmission is on a different path and calls sctp_packet_config() for the packet on path B. The DATA chunk to be retransmitted is added to this packet. - The local instance has to send another DATA chunk on path A. This depends on the application, but should be easy to trigger from a remote instance. sctp_outq_flush() notices that the path has changed again, and calls sctp_packet_config() for the packet on path A. This resets the size of the HEARTBEAT_ACK chunk, but the chunk remains in the packet. If size(HEARTBEAT_ACK) + size(DATA) > MTU - overhead, the next call to sctp_packet_transmit() causes the kernel panic => DoS. PID: 13309 TASK: f6636600 CPU: 1 COMMAND: "scriptingclient" #0 [e4d91968] crash_kexec at c0189fea #1 [e4d919b4] do_invalid_op at c0104a46 #2 [e4d91a50] error_code (via invalid_op) at c058d1a1 EAX: 0000008b EBX: f89e168d ECX: ffffff78 EDX: 00000000 EBP: e4d91ab8 DS: 007b ESI: f601e000 ES: 007b EDI: e44570e8 GS: 00e0 CS: 0060 EIP: c04b9d7c ERR: ffffffff EFLAGS: 00010286 #3 [e4d91a84] skb_over_panic at c04b9d7c #4 [e4d91a94] sctp_packet_transmit at f89e1688 #5 [e4d91ac8] sctp_packet_transmit at f89e1688 #6 [e4d91b14] sctp_packet_transmit_chunk at f89e1d23 #7 [e4d91b2c] sctp_outq_flush at f89d78f9 #8 [e4d91ba8] sctp_outq_uncork at f89d7994 #9 [e4d91bb0] sctp_cmd_interpreter at f89cce71 #10 [e4d91c00] sctp_side_effects at f89cdbff #11 [e4d91c30] sctp_do_sm at f89cdd3d #12 [e4d91cdc] sctp_assoc_bh_rcv at f89d1279 #13 [e4d91d0c] sctp_inq_push at f89d6773 #14 [e4d91d14] sctp_rcv at f89e2e5d #15 [e4d91d8c] ip_local_deliver_finish at c04ec6e5 #16 [e4d91db0] ip_local_deliver at c04ec93a #17 [e4d91dcc] ip_rcv_finish at c04ebf98 #18 [e4d91df4] ip_rcv at c04ec449 #19 [e4d91e1c] netif_receive_skb at c04c37a4 #20 [e4d91e58] e1000_receive_skb at f80a45bb #21 [e4d91e68] e1000_clean_rx_irq at f80a88b6 #22 [e4d91edc] e1000_clean at f80a799d #23 [e4d91efc] net_rx_action at c04c410a #24 [e4d91f28] __do_softirq at c0153132 #25 [e4d91f70] do_softirq at c0153290 #26 [e4d91f7c] irq_exit at c01533e0 #27 [e4d91f84] do_IRQ at c0591240 #28 [e4d91fb0] common_interrupt at c0103a2b EAX: 9af6e0c6 EBX: b0dad373 ECX: 00000005 EDX: 4d995cbc DS: 007b ESI: 598130cd ES: 007b EDI: 00b5dfc0 SS: 007b ESP: bfca6d80 EBP: bfca6df8 GS: 0033 CS: 0073 EIP: 0804b816 ERR: ffffff55 EFLAGS: 00000a86 In a similar way, the problem can also be triggered by a local user, having only the permission to establish SCTP associations. Of course, the problem can also occur during normal network operation, just by a retransmission at the wrong time. The attached patch against 2.6.36-rc4 (git repository) fixes sctp_outq_flush() by ensuring that the packet on each path is initialized only once. Furthermore, a BUG_ON() statement ensures that further problems by calling sctp_packet_reset() on packets with chunks are detected directly.