Bug 288777 (CVE-2007-3508) - VUL-0: CVE-2007-3508: glibc: ld.so integer overflow
Summary: VUL-0: CVE-2007-3508: glibc: ld.so integer overflow
Status: RESOLVED FIXED
Alias: CVE-2007-3508
Product: openSUSE 10.3
Classification: openSUSE
Component: Basesystem (show other bugs)
Version: Alpha 5
Hardware: Other Other
: P5 - None : Normal (vote)
Target Milestone: ---
Assignee: Petr Baudis
QA Contact: E-mail List
URL:
Whiteboard: CVE-2007-3508: CVSS v2 Base Score: 7....
Keywords:
Depends on:
Blocks:
 
Reported: 2007-07-02 07:42 UTC by Sebastian Krahmer
Modified: 2016-11-03 08:15 UTC (History)
2 users (show)

See Also:
Found By: ---
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments
P3 (3.37 KB, patch)
2007-07-05 09:50 UTC, Marcus Meissner
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Krahmer 2007-07-02 07:42:06 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.
- -------------------------------------------------------
Comment 1 Sebastian Krahmer 2007-07-03 07:59:49 UTC
 CVE-2007-3508
Comment 4 Sebastian Krahmer 2007-07-04 06:07:13 UTC
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.
Comment 5 Petr Baudis 2007-07-04 09:54:17 UTC
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?
Comment 6 Marcus Meissner 2007-07-05 09:49:11 UTC
There were some mails in the mailthread, I will paste them.
Comment 7 Marcus Meissner 2007-07-05 09:49:46 UTC
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

Comment 8 Marcus Meissner 2007-07-05 09:50:25 UTC
Created attachment 149789 [details]
P3

proposed patch from Jakub
Comment 9 Marcus Meissner 2007-07-05 09:51:17 UTC
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
Comment 10 Marcus Meissner 2007-07-05 09:51:34 UTC
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.
-------------------------------------------------------
Comment 11 Marcus Meissner 2007-07-05 09:51:52 UTC
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
Comment 12 Marcus Meissner 2007-07-05 09:52:19 UTC
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.
-------------------------------------------------------
Comment 13 Marcus Meissner 2007-07-05 09:52:41 UTC
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
Comment 14 Marcus Meissner 2007-07-05 09:53:17 UTC
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)
Comment 15 Marcus Meissner 2007-07-09 13:08:52 UTC
the other distribution vendors (except one) do not see it as security bug.

so we will fix it for STABLE only.
Comment 16 Petr Baudis 2007-07-09 13:12:29 UTC
I agree (my comment just suffered a mid-air collision ;). Reopening the bug since it's not fixed in STABLE yet.
Comment 17 Marcus Meissner 2007-08-02 09:49:08 UTC
any update?
Comment 18 Andreas Jaeger 2007-08-14 08:41:40 UTC
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.
Comment 19 Thomas Biege 2009-10-13 23:31:23 UTC
CVE-2007-3508: CVSS v2 Base Score: 7.2 (AV:L/AC:L/Au:N/C:C/I:C/A:C)