Home | Docs | Forums | Lists | Bugs | Planet | Store | GMN | Get Gentoo!
Not eligible to see or edit group visibility for this bug.
View Bug Activity | Format For Printing | XML | Clone This Bug
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:
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??
Proposed fix from Chris Wright: ===== net/ipv4/igmp.c 1.58 vs edited ===== --- 1.58/net/ipv4/igmp.c
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; }
Minor revision to the last patch.
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; }
New version: ===== net/ipv4/igmp.c 1.58 vs edited ===== --- 1.58/net/ipv4/igmp.c
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 */
IGMP has been assigned CAN-2004-1137
BK changesets : http://linux.bkbits.net:8080/linux-2.4/cset@41b76e94BsJKm8jhVtyDat9ZM1dXXg http://linux.bkbits.net:8080/linux-2.6/cset@41b768d1ySHbfa7cUWDle8NjDT_02A http://linux.bkbits.net:8080/linux-2.6/cset@41b76c07Ee61GkoNwMH-oOvWG2FdxA
Ok, is this cleared for declassification since it's fixed upstream then...?
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).
*** Bug 73802 has been marked as a duplicate of this bug. ***
This bug will stay closed. Public followup to bug 74384 *** This bug has been marked as a duplicate of 74384 ***