Linux Archive

Linux Archive (http://www.linux-archive.org/)
-   Ubuntu Kernel Team (http://www.linux-archive.org/ubuntu-kernel-team/)
-   -   sctp: Fix a race between ICMP protocol unreachable and connect() (http://www.linux-archive.org/ubuntu-kernel-team/542017-sctp-fix-race-between-icmp-protocol-unreachable-connect.html)

Andy Whitcroft 06-20-2011 06:19 PM

sctp: Fix a race between ICMP protocol unreachable and connect()
 
CVE-2010-4526
Race condition in the sctp_icmp_proto_unreachable function in
net/sctp/input.c in Linux kernel 2.6.11-rc2 through 2.6.33 allows
remote attackers to cause a denial of service (panic) via an ICMP
unreachable message to a socket that is already locked by a user,
which causes the socket to be freed and triggers list corruption,
related to the sctp_wait_for_connect function.

This is already fixed in everything based on v2.6.34 and above, arriving
via mainline. Following this email are patches for Hardy, and
Lucid/ti-omap4.

Note I have no clue how to confirm the backport for Hardy is good as
the bug seems to be hard to trigger and in a protocol I have no idea how
to test. Any suggestions welcome.

Proposing for Lucid/ti-omap4, and requesting testing help for Hardy.

-apw

--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team

Andy Whitcroft 06-20-2011 06:19 PM

sctp: Fix a race between ICMP protocol unreachable and connect()
 
From: Vlad Yasevich <vladislav.yasevich@hp.com>

ICMP protocol unreachable handling completely disregarded
the fact that the user may have locked the socket. It proceeded
to destroy the association, even though the user may have
held the lock and had a ref on the association. This resulted
in the following:

Attempt to release alive inet socket f6afcc00

=========================
[ BUG: held lock freed! ]
-------------------------
somenu/2672 is freeing memory f6afcc00-f6afcfff, with a lock still held
there!
(sk_lock-AF_INET){+.+.+.}, at: [<c122098a>] sctp_connect+0x13/0x4c
1 lock held by somenu/2672:
#0: (sk_lock-AF_INET){+.+.+.}, at: [<c122098a>] sctp_connect+0x13/0x4c

stack backtrace:
Pid: 2672, comm: somenu Not tainted 2.6.32-telco #55
Call Trace:
[<c1232266>] ? printk+0xf/0x11
[<c1038553>] debug_check_no_locks_freed+0xce/0xff
[<c10620b4>] kmem_cache_free+0x21/0x66
[<c1185f25>] __sk_free+0x9d/0xab
[<c1185f9c>] sk_free+0x1c/0x1e
[<c1216e38>] sctp_association_put+0x32/0x89
[<c1220865>] __sctp_connect+0x36d/0x3f4
[<c122098a>] ? sctp_connect+0x13/0x4c
[<c102d073>] ? autoremove_wake_function+0x0/0x33
[<c12209a8>] sctp_connect+0x31/0x4c
[<c11d1e80>] inet_dgram_connect+0x4b/0x55
[<c11834fa>] sys_connect+0x54/0x71
[<c103a3a2>] ? lock_release_non_nested+0x88/0x239
[<c1054026>] ? might_fault+0x42/0x7c
[<c1054026>] ? might_fault+0x42/0x7c
[<c11847ab>] sys_socketcall+0x6d/0x178
[<c10da994>] ? trace_hardirqs_on_thunk+0xc/0x10
[<c1002959>] syscall_call+0x7/0xb

This was because the sctp_wait_for_connect() would aqcure the socket
lock and then proceed to release the last reference count on the
association, thus cause the fully destruction path to finish freeing
the socket.

The simplest solution is to start a very short timer in case the socket
is owned by user. When the timer expires, we can do some verification
and be able to do the release properly.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

(backported from commit 50b5d6ad63821cea324a5a7a19854d4de1a0a819)
CVE-2010-4526
BugLink: http://bugs.launchpad.net/bugs/799828
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
include/net/sctp/sm.h | 1 +
include/net/sctp/structs.h | 3 +++
net/sctp/input.c | 22 ++++++++++++++++++----
net/sctp/sm_sideeffect.c | 35 +++++++++++++++++++++++++++++++++++
net/sctp/transport.c | 5 +++++
5 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index 925c4ac..a9d6100 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -277,6 +277,7 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
/* 2nd level prototypes */
void sctp_generate_t3_rtx_event(unsigned long peer);
void sctp_generate_heartbeat_event(unsigned long peer);
+void sctp_generate_proto_unreach_event(unsigned long peer);

void sctp_ootb_pkt_free(struct sctp_packet *);

diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index a37b837..e101032 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -983,6 +983,9 @@ struct sctp_transport {
/* Heartbeat timer is per destination. */
struct timer_list hb_timer;

+ /* Timer to handle ICMP proto unreachable envets */
+ struct timer_list proto_unreach_timer;
+
/* Since we're using per-destination retransmission timers
* (see above), we're also using per-destination "transmitted"
* queues. This probably ought to be a private struct
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 91ae463..221b946 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -410,11 +410,25 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
{
SCTP_DEBUG_PRINTK("%s
", __FUNCTION__);

- sctp_do_sm(SCTP_EVENT_T_OTHER,
- SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
- asoc->state, asoc->ep, asoc, t,
- GFP_ATOMIC);
+ if (sock_owned_by_user(sk)) {
+ if (timer_pending(&t->proto_unreach_timer))
+ return;
+ else {
+ if (!mod_timer(&t->proto_unreach_timer,
+ jiffies + (HZ/20)))
+ sctp_association_hold(asoc);
+ }
+
+ } else {
+ if (timer_pending(&t->proto_unreach_timer) &&
+ del_timer(&t->proto_unreach_timer))
+ sctp_association_put(asoc);

+ sctp_do_sm(SCTP_EVENT_T_OTHER,
+ SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
+ asoc->state, asoc->ep, asoc, t,
+ GFP_ATOMIC);
+ }
}

/* Common lookup code for icmp/icmpv6 error handler. */
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 78d1a8a..801d126 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -388,6 +388,41 @@ out_unlock:
sctp_transport_put(transport);
}

+/* Handle the timeout of the ICMP protocol unreachable timer. Trigger
+ * the correct state machine transition that will close the association.
+ */
+void sctp_generate_proto_unreach_event(unsigned long data)
+{
+ struct sctp_transport *transport = (struct sctp_transport *) data;
+ struct sctp_association *asoc = transport->asoc;
+
+ sctp_bh_lock_sock(asoc->base.sk);
+ if (sock_owned_by_user(asoc->base.sk)) {
+ SCTP_DEBUG_PRINTK("%s:Sock is busy.
", __func__);
+
+ /* Try again later. */
+ if (!mod_timer(&transport->proto_unreach_timer,
+ jiffies + (HZ/20)))
+ sctp_association_hold(asoc);
+ goto out_unlock;
+ }
+
+ /* Is this structure just waiting around for us to actually
+ * get destroyed?
+ */
+ if (asoc->base.dead)
+ goto out_unlock;
+
+ sctp_do_sm(SCTP_EVENT_T_OTHER,
+ SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
+ asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);
+
+out_unlock:
+ sctp_bh_unlock_sock(asoc->base.sk);
+ sctp_association_put(asoc);
+}
+
+
/* Inject a SACK Timeout event into the state machine. */
static void sctp_generate_sack_event(unsigned long data)
{
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index d55ce83..434439e 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -109,6 +109,11 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->hb_timer.function = sctp_generate_heartbeat_event;
peer->hb_timer.data = (unsigned long)peer;

+ /* Set up the protocol unreachable timer. */
+ init_timer(&peer->proto_unreach_timer);
+ peer->proto_unreach_timer.function = sctp_generate_proto_unreach_event;
+ peer->proto_unreach_timer.data = (unsigned long)peer;
+
/* Initialize the 64-bit random nonce sent with heartbeat. */
get_random_bytes(&peer->hb_nonce, sizeof(peer->hb_nonce));

--
1.7.4.1


--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team

Tim Gardner 06-21-2011 01:32 PM

sctp: Fix a race between ICMP protocol unreachable and connect()
 
On 06/20/2011 12:19 PM, Andy Whitcroft wrote:

CVE-2010-4526
Race condition in the sctp_icmp_proto_unreachable function in
net/sctp/input.c in Linux kernel 2.6.11-rc2 through 2.6.33 allows
remote attackers to cause a denial of service (panic) via an ICMP
unreachable message to a socket that is already locked by a user,
which causes the socket to be freed and triggers list corruption,
related to the sctp_wait_for_connect function.

This is already fixed in everything based on v2.6.34 and above, arriving
via mainline. Following this email are patches for Hardy, and
Lucid/ti-omap4.

Note I have no clue how to confirm the backport for Hardy is good as
the bug seems to be hard to trigger and in a protocol I have no idea how
to test. Any suggestions welcome.

Proposing for Lucid/ti-omap4, and requesting testing help for Hardy.

-apw



It looks like this is a race when an SCTP socket is owned or is being
shut down whilst a connection is being attempted. You ought to be able
to test by continuously opening and closing a specific port while
simultaneously and continuously attempting to connect to the port from a
networked machine.


My perl foo has atrophied, but I'll bet _you_ could whip out a simple
pair of loops to exercise this situation.


rtg
--
Tim Gardner tim.gardner@canonical.com

--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team

Stefan Bader 06-22-2011 01:03 PM

sctp: Fix a race between ICMP protocol unreachable and connect()
 
On 20.06.2011 20:19, Andy Whitcroft wrote:
> CVE-2010-4526
> Race condition in the sctp_icmp_proto_unreachable function in
> net/sctp/input.c in Linux kernel 2.6.11-rc2 through 2.6.33 allows
> remote attackers to cause a denial of service (panic) via an ICMP
> unreachable message to a socket that is already locked by a user,
> which causes the socket to be freed and triggers list corruption,
> related to the sctp_wait_for_connect function.
>
> This is already fixed in everything based on v2.6.34 and above, arriving
> via mainline. Following this email are patches for Hardy, and
> Lucid/ti-omap4.
>
> Note I have no clue how to confirm the backport for Hardy is good as
> the bug seems to be hard to trigger and in a protocol I have no idea how
> to test. Any suggestions welcome.
>
> Proposing for Lucid/ti-omap4, and requesting testing help for Hardy.
>
> -apw
>
Not sure how lucky you were with the testing. The Lucid version looks like a
clean pick. The Hardy one more or less following as far as I was able to see.

Acked-by: Stefan Bader <stefan.bader@canonical.com>

--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team


All times are GMT. The time now is 11:26 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.