

Heap Overflow in Floating Point Parsing (CVE-2013-4164) - willlll
https://www.ruby-lang.org/en/news/2013/11/22/heap-overflow-in-floating-point-parsing-cve-2013-4164/

======
comex
In case you're curious about exploitability for code execution... the bug is
that this array (Kmax = 16):

    
    
        static Bigint *freelist[Kmax+1];
    

which is indexed by the log2 of the size of the bigint, is not checked:

    
    
        static Bigint *
        Balloc(int k)
        {
            [...]
            if ((rv = freelist[k]) != 0) {
                freelist[k] = rv->next;
            }
    

If it's 0, then the allocation is done safely.

Where does Balloc get called? First with an estimate of the size required for
the whole thing, from two locations, then with steadily increasing values
starting from 1, from the mult function. With the first allocation we can
theoretically perform a complicated operation (a good thing when ASLR is
involved) to any location in ruby's bss section after freelist, but every
increase requires doubling the size of the input string, and 16 already
requires a 300k string, so going more than a few notches forward is
impractical. With the second, I think k=16 is guaranteed to get a hit, because
the next variable after freelist in the code is:

    
    
        static Bigint *p5s;
    

On my system, and probably on all, this duly shows up immediately afterwards
in the binary, and p5s is set before the allocation, so it's not null. The
code ends up "allocating" p5s and copying 64k of arbitrary data into p5s->x,
which comes from the 'private_mem' static array, also in the bss section.
Although this is certainly dangerous, on the 3 systems I tried (OS X, 64-bit
Linux, 32-bit Linux), there was much less than 64k of memory in the segment
after the array and something read-only immediately followed, so it was
guaranteed to crash before anything interesting could happen. It could be
possible to exploit anyway if another C thread were accessing the data (not
sure if mri ever does this), but the timing would be extremely difficult.

So I suspect that on most systems, this is purely a DOS, even though it
involves an overwrite of arbitrary data. However, I could definitely be
missing something, as the code is fairly complicated.

------
c3
It seems to be a fairly simple patch for 1.8 series, too:

    
    
        https://bugs.ruby-lang.org/projects/ruby-193/repository/revisions/43776
    

just a few lines truncating input in util.c.

Break your ruby here:

    
    
        JSON.parse("[1."+"1"*300000+"]")

~~~
c3
update: I just tested this; if you're on 1.8.7, you can manually apply the
patch I linked in the parent comment and recompile. There is nothing
preventing a backport.

~~~
darkhelmetlive
There's also a commit right after the merge commit to change

    
    
      if (nf > DBL_DIG * 2) continue;
    

to

    
    
      if (nf > DBL_DIG * 4) continue;

------
asdfaoeu
Strikes me as a bit silly not to patch this in 1.8 considering it's still
fairly widely used and even the default for Ubuntu 12.04 LTS.

~~~
yuhong
[https://www.ruby-lang.org/en/news/2013/06/30/we-
retire-1-8-7...](https://www.ruby-lang.org/en/news/2013/06/30/we-
retire-1-8-7/)

~~~
asdfaoeu
I can read too, announced here [https://www.ruby-
lang.org/en/news/2011/10/06/plans-for-1-8-7...](https://www.ruby-
lang.org/en/news/2011/10/06/plans-for-1-8-7/) . However I do think
discontinuing security updates after 2 years announcement for a product that
even they say is "more or less" used by everyone isn't the best decision.

~~~
lloeki
> "more or less"

... on 6 Oct 2011.

They announced their plan. It was perfectly reasonable, and Ruby 1.9 was
available way before that (2007) and at that time 1.9.3 was around the corner,
so the clock was obviously ticking way before this announcement.

Ubuntu (and Debian) choses to stick on versions with releases, and maintain
security as backported patches if need be, so the onus is now on them to
secure their system.

It is a double edged sword to choose to rely on a system that favors sticking
with older releases and rely on its own patches for bugfixing and security.
One one hand you get tight integration between packages and platform
stability, but on the other hand you get bitten back in such cases, and you
_can 't_ blame upstream for that.

~~~
rlpb
> Ubuntu (and Debian) choses to stick on versions with releases

It's not as simple as just choosing. Every single package that depends on ruby
1.8 needs to move on before ruby 1.8 can itself be removed from the Debian or
Ubuntu repositories. Either that, or the decision has to be made for laggard
dependent packages to be removed. This takes time.

In Ubuntu, ruby1.8 is in main, which means that the Ubuntu Security Team will
take care of the backported update.

~~~
lloeki
> _It 's not as simple as just choosing. Every single package that depends on
> ruby 1.8_

It is a matter of choosing, although that choice obviously goes beyond _" hey
let's bump the version of that lonely package"_. The choice I refer to is
holistic, and also covers how many packages a distribution choses to make
depend on ruby, such as the decision to package gems, with overarching
(positive _and_ negative) consequences.

~~~
rlpb
That is the cost of being able to "apt-get install <foo>" without having to
learn details of the packaging system that yet another language community
expects everyone to learn and use, for each <foo> that one wants to install.

Remember that dependencies go in multiple directions. Ruby is not necessarily
at the top of the stack. I might, for example, want to deploy my Python
application stack with puppet. Which requires Ruby.

If the choice is "don't use a distribution", then have fun with that. If the
choice is "use a distribution, but don't use it for _my_ stuff", then what
makes you so special, and how does this scale to every community that wants
the same thing?

------
Someone
So, why does ruby has its own version of strtod? From the comment in
[https://bugs.ruby-
lang.org/projects/ruby-193/repository/revi...](https://bugs.ruby-
lang.org/projects/ruby-193/repository/revisions/43776/entry/util.c) ( _"
strtod for IEEE-, VAX-, and IBM-arithmetic machines."_) it does not appear to
be for machines that don't have it in their C library.

Is it because of the incompatibility between C90 and C99 described in
[http://www.lehman.cuny.edu/cgi-bin/man-
cgi?strtod+3](http://www.lehman.cuny.edu/cgi-bin/man-cgi?strtod+3), or don't
they trust strtod to return the same results on each system? If so, where does
not trusting one's environment end?

------
ssaunier_
If you want to check your Heroku apps:

[https://gist.github.com/ssaunier/7612827/](https://gist.github.com/ssaunier/7612827/)

