Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!

Bug 73210

Summary: Serious multiple Linux <= 2.4.28 and 2.6.9 IGMP vulnerabilities (Vendor-Sec)
Product: Gentoo Security Reporter: Sune Kloppenborg Jeppesen (RETIRED) <jaervosz>
Component: KernelAssignee: Gentoo Security <security>
Status: RESOLVED DUPLICATE    
Severity: normal    
Priority: High    
Version: unspecified   
Hardware: All   
OS: All   
Whiteboard: CLASSIFIED / 20041214?
Package list:
Runtime testing required: ---

Description Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-03 04:07:41 UTC
Just reported to Vendor-Sec, no patches, PoC provided but not included here. 

There are multiple serious issues with the igmp.c code in recent kernel
versions. Here an incomplete list of bugs:

1) ip_mc_source suffers from a serious kernel deadlock & kernel memory
overwrite problem (see attached code). It is possible to decrement the
psl->sl_count counter to be 0xffffffff == -1 with the consequence that:

- a repeated call will start a loop counting from 0 to UINT_MAX causing a
kernel hang for minutes (depending on the machine speed), then the
whole kernel memory following the kmalloc'ated buffer will be shifted by 4
bytes (LOL) causing an immediate reboot.

- If properly exploited this will lead to elevated privileges.

Btw. the code there is obviously nonsense:

Comment 1 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-03 04:07:41 UTC
Just reported to Vendor-Sec, no patches, PoC provided but not included here. 

There are multiple serious issues with the igmp.c code in recent kernel
versions. Here an incomplete list of bugs:

1) ip_mc_source suffers from a serious kernel deadlock & kernel memory
overwrite problem (see attached code). It is possible to decrement the
psl->sl_count counter to be 0xffffffff == -1 with the consequence that:

- a repeated call will start a loop counting from 0 to UINT_MAX causing a
kernel hang for minutes (depending on the machine speed), then the
whole kernel memory following the kmalloc'ated buffer will be shifted by 4
bytes (LOL) causing an immediate reboot.

- If properly exploited this will lead to elevated privileges.

Btw. the code there is obviously nonsense:

                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
                        rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
                                sizeof(__u32));
                        if (rv >= 0)
                                break;
                }
                if (!rv)        /* source not found */
                        goto done;

If we had the 01.04 today I would say some people have keyboards without
the '[' and ']' brackets ;-)


2) because of the bug 1) it is possible to read huge portions of kernel
memory through ip_mc_msfget()


3) igmp_marksources() function is called in the context of an IGMP group
query and suffers from an out of bound access to kernel memory. This is
remotely exploitable if applications have bound a multicast socket.

I'm not sure but I guess that there is a large number of standard apps
that use multicast, eg. some Linux routing packages or videoconferencing,
etc.

You may check for your configuration if you are vulnerable:

/proc/net/igmp
/proc/net/mcfilter

if both files exist and are non-empty you are vulnerable.

This bug allows in the best case to remotely DoS a Linux machine with just
a moderate flow of prepared IGMP packets.

In the worst case (the socket buffer allocated for the packet is at the
end of kernel accessible memory), the Linux machine may be crashed
remotely.

4) I think there are more bugs and more or less subtle races in that code.


And seriously, please save me from the 'I have a patch for X' 'I have a
patch for Y' mentality, I feel like that code or at least parts of it have
been done by people _without_ any elementary C and kernel API & principles
knowledge. It _must_ be completely reaudited. I really wonder, since I
remember that it was mostly clean in .22 or .23 or so, so who the hell is
breaking it again and again and why??
Comment 2 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-04 05:39:30 UTC
Proposed fix from Chris Wright:

===== net/ipv4/igmp.c 1.58 vs edited =====
--- 1.58/net/ipv4/igmp.c
Comment 3 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-04 05:39:30 UTC
Proposed fix from Chris Wright:

===== net/ipv4/igmp.c 1.58 vs edited =====
--- 1.58/net/ipv4/igmp.c        2004-11-09 16:44:25 -08:00
+++ edited/net/ipv4/igmp.c      2004-12-04 01:14:53 -08:00
@@ -1774,16 +1774,16 @@ int ip_mc_source(int add, int omode, str
 
        psl = pmc->sflist;
        if (!add) {
-               if (!psl)
+               if (!psl || !psl->sl_count)
                        goto done;
-               rv = !0;
+               rv = 1;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+                       rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                                sizeof(__u32));
-                       if (rv >= 0)
+                       if (rv >= 0)    /* array is sorted */
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -1825,7 +1825,7 @@ int ip_mc_source(int add, int omode, str
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+               rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                        sizeof(__u32));
                if (rv >= 0)
                        break;
===== net/ipv6/mcast.c 1.71 vs edited =====
--- 1.71/net/ipv6/mcast.c       2004-11-11 15:07:25 -08:00
+++ edited/net/ipv6/mcast.c     2004-12-04 01:27:20 -08:00
@@ -387,16 +387,16 @@ int ip6_mc_source(int add, int omode, st
 
        psl = pmc->sflist;
        if (!add) {
-               if (!psl)
+               if (!psl || !psl->sl_count)
                        goto done;
-               rv = !0;
+               rv = 1;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, group,
+                       rv = memcmp(&psl->sl_addr[i], source,
                                sizeof(struct in6_addr));
-                       if (rv >= 0)
+                       if (rv >= 0)    /* array is sorted */
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -437,7 +437,7 @@ int ip6_mc_source(int add, int omode, st
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, group, sizeof(struct in6_addr));
+               rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr));
                if (rv >= 0)
                        break;
        }
Comment 4 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-06 23:16:56 UTC
Minor revision to the last patch. 
Comment 5 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-06 23:16:56 UTC
Minor revision to the last patch.  Eliminates some no-op changes.

===== net/ipv4/igmp.c 1.58 vs edited =====
--- 1.58/net/ipv4/igmp.c        2004-11-09 16:44:25 -08:00
+++ edited/net/ipv4/igmp.c      2004-12-06 18:43:54 -08:00
@@ -1778,12 +1778,12 @@ int ip_mc_source(int add, int omode, str
                        goto done;
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+                       rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                                sizeof(__u32));
-                       if (rv >= 0)
+                       if (rv >= 0)    /* array is sorted */
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -1825,7 +1825,7 @@ int ip_mc_source(int add, int omode, str
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+               rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                        sizeof(__u32));
                if (rv >= 0)
                        break;
===== net/ipv6/mcast.c 1.71 vs edited =====
--- 1.71/net/ipv6/mcast.c       2004-11-11 15:07:25 -08:00
+++ edited/net/ipv6/mcast.c     2004-12-06 18:43:54 -08:00
@@ -391,12 +391,12 @@ int ip6_mc_source(int add, int omode, st
                        goto done;
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, group,
+                       rv = memcmp(&psl->sl_addr[i], source,
                                sizeof(struct in6_addr));
-                       if (rv >= 0)
+                       if (rv >= 0)    /* array is sorted */
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -437,7 +437,7 @@ int ip6_mc_source(int add, int omode, st
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, group, sizeof(struct in6_addr));
+               rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr));
                if (rv >= 0)
                        break;
        }
Comment 6 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-11 00:47:40 UTC
New version:

===== net/ipv4/igmp.c 1.58 vs edited =====
--- 1.58/net/ipv4/igmp.c
Comment 7 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-11 00:47:40 UTC
New version:

===== net/ipv4/igmp.c 1.58 vs edited =====
--- 1.58/net/ipv4/igmp.c        2004-11-09 16:44:25 -08:00
+++ edited/net/ipv4/igmp.c      2004-12-10 15:16:17 -08:00
@@ -1778,12 +1778,12 @@ int ip_mc_source(int add, int omode, str
                        goto done;
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+                       rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                                sizeof(__u32));
-                       if (rv >= 0)
+                       if (rv == 0)
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -1825,9 +1825,9 @@ int ip_mc_source(int add, int omode, str
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, &mreqs->imr_multiaddr,
+               rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
                        sizeof(__u32));
-               if (rv >= 0)
+               if (rv == 0)
                        break;
        }
        if (rv == 0)            /* address already there is an error */
===== net/ipv6/mcast.c 1.71 vs edited =====
--- 1.71/net/ipv6/mcast.c       2004-11-11 15:07:25 -08:00
+++ edited/net/ipv6/mcast.c     2004-12-10 17:20:46 -08:00
@@ -391,12 +391,12 @@ int ip6_mc_source(int add, int omode, st
                        goto done;
                rv = !0;
                for (i=0; i<psl->sl_count; i++) {
-                       rv = memcmp(&psl->sl_addr, group,
+                       rv = memcmp(&psl->sl_addr[i], source,
                                sizeof(struct in6_addr));
-                       if (rv >= 0)
+                       if (rv == 0)
                                break;
                }
-               if (!rv)        /* source not found */
+               if (rv)         /* source not found */
                        goto done;
 
                /* update the interface filter */
@@ -437,8 +437,8 @@ int ip6_mc_source(int add, int omode, st
        }
        rv = 1; /* > 0 for insert logic below if sl_count is 0 */
        for (i=0; i<psl->sl_count; i++) {
-               rv = memcmp(&psl->sl_addr, group, sizeof(struct in6_addr));
-               if (rv >= 0)
+               rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr));
+               if (rv == 0)
                        break;
        }
        if (rv == 0)            /* address already there is an error */
Comment 8 Sune Kloppenborg Jeppesen (RETIRED) gentoo-dev 2004-12-13 00:35:06 UTC
IGMP has been assigned  CAN-2004-1137
Comment 10 Tim Yamin (RETIRED) gentoo-dev 2004-12-13 11:21:06 UTC
Ok, is this cleared for declassification since it's fixed upstream then...?
Comment 11 Thierry Carrez (RETIRED) gentoo-dev 2004-12-14 06:57:40 UTC
This bug is and will stay classified (quoting emails sent to v-s and requesting secret). Another one will be opened to handle the issue when it will be public.

This is however semi-public since the fixes are out there, so we can start including patches in our trees too. Any publicity about it should however wait for advisory publication (due Dec 14 20:00 UTC).
Comment 12 Thierry Carrez (RETIRED) gentoo-dev 2004-12-14 06:59:54 UTC
*** Bug 73802 has been marked as a duplicate of this bug. ***
Comment 13 Thierry Carrez (RETIRED) gentoo-dev 2004-12-14 09:03:35 UTC
This bug will stay closed. Public followup to bug 74384

*** This bug has been marked as a duplicate of 74384 ***