Bugzilla – Bug 288777
VUL-0: CVE-2007-3508: glibc: ld.so integer overflow
Last modified: 2016-11-03 08:15:55 UTC
Date: Fri, 29 Jun 2007 16:42:19 -0400 From: Josh Bressers <bressers@redhat.com> To: <vendor-sec@lst.de> Subject: [vendor-sec] FWD: [taviso@gentoo.org: potential integer overflow in ld.so] Per Tavis' request: ------- Forwarded Message Date: Fri, 29 Jun 2007 21:38:55 +0100 From: Tavis Ormandy <taviso@gentoo.org> To: Josh Bressers <bressers@redhat.com> Subject: [taviso@gentoo.org: potential integer overflow in ld.so] Hi Josh, sorry to bother you, but I'm having some trouble posting to vendor-sec, if my post hasnt arrived by the time you receive this, would you mind forwarding it to the list for me? Thanks for your help, Tavis. - ----- Forwarded message from Tavis Ormandy <taviso@gentoo.org> ----- Date: Fri, 29 Jun 2007 20:38:19 +0100 From: Tavis Ormandy <taviso@gentoo.org> To: vendor-sec@lst.de Subject: potential integer overflow in ld.so User-Agent: Mutt/1.5.13 (2006-08-11) Hello, I'm concerned there may be an integer overflow in ld.so accessible via LD_HWCAP_MASK (which is honoured for setuid binaries), $ strace -emmap2 -f env -i LD_HWCAP_MASK=$((0xffffffff)) su ... mmap2(NULL, 335544320, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xa4000000 $ strace -emmap2 -f env -i LD_HWCAP_MASK=$((0x7fffffff)) su ... mmap2(NULL, 2181038080, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, - -1, 0) = -1 ENOMEM (Cannot allocate memory) Inconsistency detected by ld.so: dl-minimal.c: 84: __libc_memalign: Assertion `page != ((void *) -1)' failed! Process 22280 detached $ env -i LD_HWCAP_MASK=$((0xffffffff)) su Segmentation fault (Note some people who have tested this report it doesnt crash reliably, presumably due to system configuration, it works on my workstation, and I've tried it on default installs of rhel5 and ubuntu and confirmed it) There seem to be numerous locations inside elf/dl-*.c where this can hit, and some of the routines dont look robust against integer overflows, but an easy solution should be ignoring LD_HWCAP_MASK for setuid? Thanks, Tavis. - -- - ------------------------------------- taviso@sdf.lonestar.org | finger me for my pgp key. - -------------------------------------------------------
CVE-2007-3508
There is a discussion whether this is security relevant anyways. Up to now it looks like its only something we need for STABLE; so no updates necessary.
Well, I on one hand I'll be glad because all-versions update is a lot of work ;), on the other hand, I _do_ think that ability to easily cause process running on root to allocate (and _use_) arbitrary amount of memory (and possibly CPU cycles) is a minor security issue. Or are ulimits meant just as a safety measure nowadays, not as a security mechanism?
There were some mails in the mailthread, I will paste them.
From: Jakub Jelinek <jakub@redhat.com> To: vendor-sec@lst.de Subject: Re: [vendor-sec] potential integer overflow in ld.so Reply-To: Jakub Jelinek <jakub@redhat.com> User-Agent: Mutt/1.4.1i Errors-To: vendor-sec-admin@lst.de Date: Sun, 1 Jul 2007 17:40:22 -0400 [-- Anhang #1 --] [-- Typ: text/plain, Kodierung: 7bit, Größe: 5,5K --] On Sat, Jun 30, 2007 at 12:25:26PM +0100, Tavis Ormandy wrote: > On Sat, Jun 30, 2007 at 07:05:03AM -0400, Jakub Jelinek wrote: > > The bug in ld.so with LD_HWCAP_MASK containing many bits (on CPUs with > > many hwcap bits set) IMHO can't be exploited, all that happens is: > > 1) either the size is too large, but doesn't overflow (usually that's what > > happens say with LD_HWCAP_MASK=$((0xffffffff)) on x86_64) - then depending > > on how your glibc is built, you'll either get an assertion failure (if > > glibc is built with assertion checking, apparently some distros built > > glibc that way) and immediate exit during ld.so startup, or a segfault > > 2) if the size of malloc for hwcap array computation overflows, then > > you should just get a segfault when filling up the array > > I'll fix these bugs hopefully tonight, but I don't think you can actually > > exploit this. > > > > "should" just get a segfault, but how certain are you that this cant be > caused to wrap to a value that isnt enough to write out of bounds, but > is enough to damage the heap, and thus indirectly cause an exploitable > condition? > > I'm not claiming this is trivially exploitable, but lots of integer > overflows behave this way, I dont see why this one is different. > > It seems possible to me, but I admit I havnt reproduced it. Ok, let me dive into the details. The only problematic platform is i?86, all other platforms are either 64-bit (where the overflow can't happen, no platform defines more than 36 bits or so), or have either none or very few supported hwcaps (ppc32 has most of these, but still not enough to overflow). The important chunks from _dl_important_hwcaps are: /* Determine how many important bits are set. */ uint64_t masked = GLRO(dl_hwcap) & GLRO(dl_hwcap_mask); size_t cnt = platform != NULL; ... /* Count the number of bits set in the masked value. */ for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n) if ((masked & (1ULL << n)) != 0) ++cnt; ... /* For TLS enabled builds always add 'tls'. */ ++cnt; ... /* Determine the total size of all strings together. */ if (cnt == 1) total = temp[0].len + 1; else { total = (1UL << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2); for (n = 1; n + 1 < cnt; ++n) total += (1UL << (cnt - 3)) * (temp[n].len + 1); } /* The result structure: we use a very compressed way to store the various combinations of capability names. */ *sz = 1 << cnt; result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total); if (result == NULL) _dl_signal_error (ENOMEM, NULL, NULL, N_("cannot create capability list")); ... result[1].str = result[0].str = cp = (char *) (result + *sz); #define add(idx) \ cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1); if (cnt == 2) { add (1); add (0); } else { n = 1 << (cnt - 1); do { n -= 2; /* We always add the last string. */ add (cnt - 1); GLRO(dl_hwcap) is actual hwcap mask supplied by the kernel (see LD_SHOW_AUXV=1 /bin/true | grep HWCAP ), GLRO(dl_hwcap_mask) is LD_HWCAP_MASK (due to bug in ld.so any value bigger than LONG_MAX is actually parsed as 0xffffffff). malloc used here is ld.so's minimal version, as libc.so isn't loaded yet at this point. On i?86, platform will be non-NULL (i386, i486, i586 or i686), so cnt will be either popcountll (dl_hwcap & dl_hwcap_mask) + 2 or popcountll (dl_hwcap & dl_hwcap_mask) + 3 (1 for the platform string, 1 for "tls" and optionally 1 for "nosegneg" in xen kernels). If *sz * sizeof (*result) + total doesn't overflow anywhere through its computation, but is too big and mmap fails, then either we hit assertion failure and therefore instant quit, or in -DNDEBUG=1 builds malloc returns -1 and so result[0].str = (char *) (result + *sz); segfaults or sigills instantly (so 64-bit arches ought to be safe). If it does overflow, we have two cases. Either cnt is 29 or bigger (talking about 32-bit arches), then we are safe too - we write to result[0].str and (result + *sz) overflows and thus equals to result, so ld.so starts overwriting memory from there upwards and eventually hits end of page and segfaults. If cnt is 28 or in some cases 27, sizeof (*result) << cnt doesn't overflow, for 28 computation of total does though and for 27, although *sz + sizeof (*result) + total is 0xexxxxxxx or 0xfxxxxxxx without overflowing, we might hit the bug in dl-minimal.c's __libc_memalign. In these cases ld.so will write two words at the beginning of the allocation and then skip sizeof (*result) << cnt bytes (i.e. 2GB for cnt == 28 or 1GB for cnt == 27) and then start writing data there. When cnt == 28, for most hwcap bits the overflown value is actually bigger than 2GB, so if that region was mmapped, there should be some gap after the allocation and thus it shouldn't reach stack pages. To successfully explot this, you'd need to have the allocated region (either end of ld.so's data segment or whatever a successful mmap returns) 2GB (resp. 1GB) below stack (very unlikely and the attacked doesn't have control over it) and overwrite there inside a mempcpy mempcpy's return address. But you don't have much control over what is written over there, it will be one of the ld.so's hardcoded hwcap strings, possibly several concatenated with /. Nothing but ld.so and the program are loaded in memory at that point, ld.so isn't initialized. Attached is a very lightly tested unofficial fix: Jakub
Created attachment 149789 [details] P3 proposed patch from Jakub
To: Jakub Jelinek <jakub@redhat.com> Cc: vendor-sec@lst.de From: Josh Bressers <bressers@redhat.com> Subject: Re: [vendor-sec] potential integer overflow in ld.so Comments: In-reply-to Jakub Jelinek <jakub@redhat.com> message dated "Sun, 01 Jul 2007 17:40:22 -0400." Errors-To: vendor-sec-admin@lst.de Date: Mon, 02 Jul 2007 14:26:22 -0400 > > Ok, let me dive into the details. > The only problematic platform is i?86, all other platforms are either > 64-bit (where the overflow can't happen, no platform defines more than 36 > bits or so), or have either none or very few supported hwcaps (ppc32 has > most of these, but still not enough to overflow). > I had a chat with Jakub today regarding this flaw. Red Hat won't be considering this a security flaw. It's really just a crash which has no significant impact. The notable points for this decision are as such: * The hwcap strings aren't under attacker's control, and they contain only lower case letters, /, digits and '\0' * libc isn't loaded yet and ld.so isn't initialized (no return into libc exploits) And to quote Jakub If you don't return to ld.so or binary (i.e. don't change control flow during that time), the program will just segfault as it fills the string area and then continues to fill everything from the start of the allocation to the beginning of the string area so what Tavis said - damage heap and see bad things in main() are not an issue; you won't reach main() Is anyone planning on calling this a security flaw? Thanks. -- JB
From: Tavis Ormandy <taviso@gentoo.org> To: Josh Bressers <bressers@redhat.com> Cc: Jakub Jelinek <jakub@redhat.com>, vendor-sec@lst.de Subject: Re: [vendor-sec] potential integer overflow in ld.so Mail-Followup-To: Josh Bressers <bressers@redhat.com>, Jakub Jelinek <jakub@redhat.com>, vendor-sec@lst.de User-Agent: Mutt/1.5.13 (2006-08-11) Errors-To: vendor-sec-admin@lst.de Date: Mon, 2 Jul 2007 19:42:16 +0100 On Mon, Jul 02, 2007 at 02:26:22PM -0400, Josh Bressers wrote: > Is anyone planning on calling this a security flaw? > Yes, gentoo will be. For various reasons, we're not convinced its not exploitable. Please dont commit any changes to a publically accessible cvs until we've had a chance to prepare an advisory. We'll be issuing an advisory along the lines of "This update is provided as a precaution against currently unknown attack vectors". I'm still playing with this vulnerability on my workstation, and look forward to proving you wrong :) (I'll let you know if I get anywhere). Thanks, Tavis. -- ------------------------------------- taviso@sdf.lonestar.org | finger me for my pgp key. -------------------------------------------------------
To: Tavis Ormandy <taviso@gentoo.org> Cc: Jakub Jelinek <jakub@redhat.com>, vendor-sec@lst.de From: Josh Bressers <bressers@redhat.com> Subject: Re: [vendor-sec] potential integer overflow in ld.so Comments: In-reply-to Tavis Ormandy <taviso@gentoo.org> message dated "Mon, 02 Jul 2007 19:42:16 +0100." Errors-To: vendor-sec-admin@lst.de Date: Mon, 02 Jul 2007 18:21:00 -0400 > > Yes, gentoo will be. For various reasons, we're not convinced its not > exploitable. Please dont commit any changes to a publically accessible > cvs until we've had a chance to prepare an advisory. > Can you elaborate on these reasons? Jakub makes a rather compelling argument, but if there's something I'm missing, I would like to know. Thanks. -- JB
From: Tavis Ormandy <taviso@gentoo.org> To: Josh Bressers <bressers@redhat.com> Cc: Jakub Jelinek <jakub@redhat.com>, vendor-sec@lst.de Subject: Re: [vendor-sec] potential integer overflow in ld.so Mail-Followup-To: Josh Bressers <bressers@redhat.com>, Jakub Jelinek <jakub@redhat.com>, vendor-sec@lst.de User-Agent: Mutt/1.5.13 (2006-08-11) Errors-To: vendor-sec-admin@lst.de Date: Tue, 3 Jul 2007 00:21:00 +0100 [-- PGP Ausgabe folgt (aktuelle Zeit: Do 05 Jul 2007 11:51:51 CEST) --] gpg: Signature made Di 03 Jul 2007 01:21:00 CEST using RSA key ID 2690FD71 gpg: Bitte ein --check-trustdb durchführen gpg: Good signature from "Tavis Ormandy <taviso@gentoo.org>" gpg: aka "Tavis Ormandy <taviso@sdf.lonestar.org>" gpg: WARNUNG: Dieser Schlüssel trägt keine vertrauenswürdige Signatur! gpg: Es gibt keinen Hinweis, daß die Signatur wirklich dem vorgeblichen Besitzer gehört. Haupt-Fingerabdruck = 2E 99 A2 DB 6A DC D4 A5 B4 48 AE A2 B1 46 05 B2 [-- Ende der PGP-Ausgabe --] [-- Die folgenden Daten sind signiert --] On Mon, Jul 02, 2007 at 06:21:00PM -0400, Josh Bressers wrote: > > > > Yes, gentoo will be. For various reasons, we're not convinced its not > > exploitable. Please dont commit any changes to a publically accessible > > cvs until we've had a chance to prepare an advisory. > > > > Can you elaborate on these reasons? Jakub makes a rather compelling > argument, but if there's something I'm missing, I would like to know. > > Thanks. It's a heap overflow in all dynamically linked suid/sgid applications, i'm surprised I have to say more to convince you this is a security issue :) I dont think your notable points are particularly notable: "The hwcap strings aren't under attacker's control" * this isnt particularly restrictive, far more restrictive bugs have been successfully exploited in the past, such as single nul bytes. "libc isn't loaded yet" * return to libc isnt the only exploit technique. I also suspect I can get the mempcpy to return, I'm working on this right now. Thanks, Tavis. -- ------------------------------------- taviso@sdf.lonestar.org | finger me for my pgp key. -------------------------------------------------------
From: Jakub Jelinek <jakub@redhat.com> To: Josh Bressers <bressers@redhat.com>, vendor-sec@lst.de Subject: Re: [vendor-sec] potential integer overflow in ld.so Reply-To: Jakub Jelinek <jakub@redhat.com> User-Agent: Mutt/1.4.1i Errors-To: vendor-sec-admin@lst.de Date: Tue, 3 Jul 2007 04:13:02 -0400 On Tue, Jul 03, 2007 at 12:21:00AM +0100, Tavis Ormandy wrote: > It's a heap overflow in all dynamically linked suid/sgid applications, > i'm surprised I have to say more to convince you this is a security > issue :) Except that there is no heap yet, minimal malloc implementation that is used and that never frees what has been allocated except the last chunk. When ld.so loads libc.so (it would need to get through till the end of this routine at least), it switches to malloc in libc.so which initializes its heap. > I dont think your notable points are particularly notable: > > "The hwcap strings aren't under attacker's control" > * this isnt particularly restrictive, far more restrictive bugs have > been successfully exploited in the past, such as single nul bytes. > > "libc isn't loaded yet" > * return to libc isnt the only exploit technique. Sure, but if you don't alter control flow, the code will segfault after the add(xxx) loop: /* Now we are ready to install the string pointers and length. */ for (n = 0; n < (1UL << cnt); ++n) result[n].len = 0; Jakub
To: vendor-sec@lst.de Cc: Jakub Jelinek <jakub@redhat.com> From: Josh Bressers <bressers@redhat.com> Subject: Re: [vendor-sec] potential integer overflow in ld.so Comments: In-reply-to Moritz Muehlenhoff <jmm@inutil.org> message dated "Tue, 03 Jul 2007 23:05:43 +0200." Errors-To: vendor-sec-admin@lst.de Date: Tue, 03 Jul 2007 19:30:55 -0400 > > > > Is anyone planning on calling this a security flaw? > > Debian doesn't; our glibc experts agree it's not a security problem. > This is now public: http://marc.info/?l=full-disclosure&m=118349602707955&w=2 -- JB (sadly enough marked up as critical by using "code execution" words -Marcus)
the other distribution vendors (except one) do not see it as security bug. so we will fix it for STABLE only.
I agree (my comment just suffered a mid-air collision ;). Reopening the bug since it's not fixed in STABLE yet.
any update?
The following patch is in our glibc for 10.3: 2007-07-01 Jakub Jelinek <jakub@redhat.com> * elf/dl-sysdep.c (_dl_important_hwcaps): Add integer overflow check. * elf/dl-minimal.c (__libc_memalign): Likewise. Handle malloc (0). Return NULL if mmap failed instead of asserting it does not. (calloc): Check for integer overflow. * elf/dl-minimal.c (__strtoul_internal): Fix parsing of numbers bigger than LONG_MAX / 10. Therefore this issues is fixed.
CVE-2007-3508: CVSS v2 Base Score: 7.2 (AV:L/AC:L/Au:N/C:C/I:C/A:C)