Ticket #3681: data_dump_infinite_recurse.diff

File data_dump_infinite_recurse.diff, 11.0 KB (added by ken@…, 10 years ago)

debian backport of hte upstream fix.

  • MANIFEST

    From 92ad49d8266598fece30e2bdf721969112212e54 Mon Sep 17 00:00:00 2001
    From: Tony Cook <tony@develop-help.com>
    Date: Mon, 30 Jun 2014 12:16:03 +1000
    Subject: don't recurse infinitely in Data::Dumper
    
    Add a configuration variable/option to limit recursion when dumping
    deep data structures.
    
    Defaults the limit to 1000, which can be reduced or increase, or
    eliminated by setting it to 0.
    
    This patch addresses CVE-2014-4330.  This bug was found and
    reported by: LSE Leading Security Experts GmbH employee Markus
    Vervier.
    
    [Patch backported to 5.20 by Dominic Hargreaves for Debian.]
    
    Origin: http://perl5.git.perl.org/perl.git/commit/19be3be6968e2337bcdfe480693fff795ecd1304
    Patch-Name: fixes/data_dump_infinite_recurse.diff
    ---
     MANIFEST                     |  1 +
     dist/Data-Dumper/Dumper.pm   | 23 ++++++++++++++++++++++
     dist/Data-Dumper/Dumper.xs   | 32 ++++++++++++++++++++++---------
     dist/Data-Dumper/t/recurse.t | 45 ++++++++++++++++++++++++++++++++++++++++++++
     4 files changed, 92 insertions(+), 9 deletions(-)
     create mode 100644 dist/Data-Dumper/t/recurse.t
    
    diff --git a/MANIFEST b/MANIFEST
    index f4f7404..867ea7d 100644
    a b dist/Data-Dumper/t/perl-74170.t Regression test for stack reallocation  
    29942994dist/Data-Dumper/t/purity_deepcopy_maxdepth.t   See if three Data::Dumper functions work
    29952995dist/Data-Dumper/t/qr.t         See if Data::Dumper works with qr|/|
    29962996dist/Data-Dumper/t/quotekeys.t  See if Data::Dumper::Quotekeys works
     2997dist/Data-Dumper/t/recurse.t    See if Data::Dumper::Maxrecurse works
    29972998dist/Data-Dumper/t/seen.t       See if Data::Dumper::Seen works
    29982999dist/Data-Dumper/t/sortkeys.t   See if Data::Dumper::Sortkeys works
    29993000dist/Data-Dumper/t/sparseseen.t See if Data::Dumper::Sparseseen works
  • dist/Data-Dumper/Dumper.pm

    diff --git a/dist/Data-Dumper/Dumper.pm b/dist/Data-Dumper/Dumper.pm
    index 7c8a72c..49121ce 100644
    a b $Useperl = 0 unless defined $Useperl;  
    5656$Sortkeys   = 0         unless defined $Sortkeys;
    5757$Deparse    = 0         unless defined $Deparse;
    5858$Sparseseen = 0         unless defined $Sparseseen;
     59$Maxrecurse = 1000      unless defined $Maxrecurse;
    5960
    6061#
    6162# expects an arrayref of values to be dumped.
    sub new {  
    9293        'bless'    => $Bless,    # keyword to use for "bless"
    9394#        expdepth   => $Expdepth,   # cutoff depth for explicit dumping
    9495        maxdepth   => $Maxdepth,   # depth beyond which we give up
     96        maxrecurse => $Maxrecurse, # depth beyond which we abort
    9597        useperl    => $Useperl,    # use the pure Perl implementation
    9698        sortkeys   => $Sortkeys,   # flag or filter for sorting hash keys
    9799        deparse    => $Deparse,    # use B::Deparse for coderefs
    sub _dump {  
    350352      return qq['$val'];
    351353    }
    352354
     355    # avoid recursing infinitely [perl #122111]
     356    if ($s->{maxrecurse} > 0
     357        and $s->{level} >= $s->{maxrecurse}) {
     358        die "Recursion limit of $s->{maxrecurse} exceeded";
     359    }
     360
    353361    # we have a blessed ref
    354362    my ($blesspad);
    355363    if ($realpack and !$no_bless) {
    sub Maxdepth {  
    680688  defined($v) ? (($s->{'maxdepth'} = $v), return $s) : $s->{'maxdepth'};
    681689}
    682690
     691sub Maxrecurse {
     692  my($s, $v) = @_;
     693  defined($v) ? (($s->{'maxrecurse'} = $v), return $s) : $s->{'maxrecurse'};
     694}
     695
    683696sub Useperl {
    684697  my($s, $v) = @_;
    685698  defined($v) ? (($s->{'useperl'} = $v), return $s) : $s->{'useperl'};
    no maximum depth.  
    11051118
    11061119=item *
    11071120
     1121$Data::Dumper::Maxrecurse  I<or>  $I<OBJ>->Maxrecurse(I<[NEWVAL]>)
     1122
     1123Can be set to a positive integer that specifies the depth beyond which
     1124recursion into a structure will throw an exception.  This is intended
     1125as a security measure to prevent perl running out of stack space when
     1126dumping an excessively deep structure.  Can be set to 0 to remove the
     1127limit.  Default is 1000.
     1128
     1129=item *
     1130
    11081131$Data::Dumper::Useperl  I<or>  $I<OBJ>->Useperl(I<[NEWVAL]>)
    11091132
    11101133Can be set to a boolean value which controls whether the pure Perl
  • dist/Data-Dumper/Dumper.xs

    diff --git a/dist/Data-Dumper/Dumper.xs b/dist/Data-Dumper/Dumper.xs
    index 12c4ebd..49937be 100644
    a b static I32 DD_dump (pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval,  
    2828                    SV *pad, SV *xpad, SV *apad, SV *sep, SV *pair,
    2929                    SV *freezer, SV *toaster,
    3030                    I32 purity, I32 deepcopy, I32 quotekeys, SV *bless,
    31                     I32 maxdepth, SV *sortkeys, int use_sparse_seen_hash, I32 useqq);
     31                    I32 maxdepth, SV *sortkeys, int use_sparse_seen_hash, I32 useqq, IV maxrecurse);
    3232
    3333#ifndef HvNAME_get
    3434#define HvNAME_get HvNAME
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    412412        AV *postav, I32 *levelp, I32 indent, SV *pad, SV *xpad,
    413413        SV *apad, SV *sep, SV *pair, SV *freezer, SV *toaster, I32 purity,
    414414        I32 deepcopy, I32 quotekeys, SV *bless, I32 maxdepth, SV *sortkeys,
    415         int use_sparse_seen_hash, I32 useqq)
     415        int use_sparse_seen_hash, I32 useqq, IV maxrecurse)
    416416{
    417417    char tmpbuf[128];
    418418    Size_t i;
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    589589            return 1;
    590590        }
    591591
     592        if (maxrecurse > 0 && *levelp >= maxrecurse) {
     593            croak("Recursion limit of %" IVdf " exceeded", maxrecurse);
     594        }
     595
    592596        if (realpack && !no_bless) {                            /* we have a blessed ref */
    593597            STRLEN blesslen;
    594598            const char * const blessstr = SvPV(bless, blesslen);
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    674678                DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
    675679                        postav, levelp, indent, pad, xpad, apad, sep, pair,
    676680                        freezer, toaster, purity, deepcopy, quotekeys, bless,
    677                         maxdepth, sortkeys, use_sparse_seen_hash, useqq);
     681                        maxdepth, sortkeys, use_sparse_seen_hash, useqq,
     682                        maxrecurse);
    678683                sv_catpvn(retval, ")}", 2);
    679684            }                                                /* plain */
    680685            else {
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    682687                DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
    683688                        postav, levelp, indent, pad, xpad, apad, sep, pair,
    684689                        freezer, toaster, purity, deepcopy, quotekeys, bless,
    685                         maxdepth, sortkeys, use_sparse_seen_hash, useqq);
     690                        maxdepth, sortkeys, use_sparse_seen_hash, useqq,
     691                        maxrecurse);
    686692            }
    687693            SvREFCNT_dec(namesv);
    688694        }
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    694700            DD_dump(aTHX_ ival, SvPVX_const(namesv), SvCUR(namesv), retval, seenhv,
    695701                    postav, levelp,     indent, pad, xpad, apad, sep, pair,
    696702                    freezer, toaster, purity, deepcopy, quotekeys, bless,
    697                     maxdepth, sortkeys, use_sparse_seen_hash, useqq);
     703                    maxdepth, sortkeys, use_sparse_seen_hash, useqq,
     704                    maxrecurse);
    698705            SvREFCNT_dec(namesv);
    699706        }
    700707        else if (realtype == SVt_PVAV) {
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    767774                DD_dump(aTHX_ elem, iname, ilen, retval, seenhv, postav,
    768775                        levelp, indent, pad, xpad, apad, sep, pair,
    769776                        freezer, toaster, purity, deepcopy, quotekeys, bless,
    770                         maxdepth, sortkeys, use_sparse_seen_hash, useqq);
     777                        maxdepth, sortkeys, use_sparse_seen_hash,
     778                        useqq, maxrecurse);
    771779                if (ix < ixmax)
    772780                    sv_catpvn(retval, ",", 1);
    773781            }
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    970978                DD_dump(aTHX_ hval, SvPVX_const(sname), SvCUR(sname), retval, seenhv,
    971979                        postav, levelp, indent, pad, xpad, newapad, sep, pair,
    972980                        freezer, toaster, purity, deepcopy, quotekeys, bless,
    973                         maxdepth, sortkeys, use_sparse_seen_hash, useqq);
     981                        maxdepth, sortkeys, use_sparse_seen_hash, useqq,
     982                        maxrecurse);
    974983                SvREFCNT_dec(sname);
    975984                Safefree(nkey_buffer);
    976985                if (indent >= 2)
    DD_dump(pTHX_ SV *val, const char *name, STRLEN namelen, SV *retval, HV *seenhv,  
    11791188                                seenhv, postav, &nlevel, indent, pad, xpad,
    11801189                                newapad, sep, pair, freezer, toaster, purity,
    11811190                                deepcopy, quotekeys, bless, maxdepth,
    1182                                 sortkeys, use_sparse_seen_hash, useqq);
     1191                                sortkeys, use_sparse_seen_hash, useqq,
     1192                                maxrecurse);
    11831193                        SvREFCNT_dec(e);
    11841194                    }
    11851195                }
    Data_Dumper_Dumpxs(href, ...)  
    12691279            SV *val, *name, *pad, *xpad, *apad, *sep, *pair, *varname;
    12701280            SV *freezer, *toaster, *bless, *sortkeys;
    12711281            I32 purity, deepcopy, quotekeys, maxdepth = 0;
     1282            IV maxrecurse = 1000;
    12721283            char tmpbuf[1024];
    12731284            I32 gimme = GIMME;
    12741285            int use_sparse_seen_hash = 0;
    Data_Dumper_Dumpxs(href, ...)  
    13551366                    bless = *svp;
    13561367                if ((svp = hv_fetch(hv, "maxdepth", 8, FALSE)))
    13571368                    maxdepth = SvIV(*svp);
     1369                if ((svp = hv_fetch(hv, "maxrecurse", 10, FALSE)))
     1370                    maxrecurse = SvIV(*svp);
    13581371                if ((svp = hv_fetch(hv, "sortkeys", 8, FALSE))) {
    13591372                    sortkeys = *svp;
    13601373                    if (! SvTRUE(sortkeys))
    Data_Dumper_Dumpxs(href, ...)  
    14341447                    DD_dump(aTHX_ val, SvPVX_const(name), SvCUR(name), valstr, seenhv,
    14351448                            postav, &level, indent, pad, xpad, newapad, sep, pair,
    14361449                            freezer, toaster, purity, deepcopy, quotekeys,
    1437                             bless, maxdepth, sortkeys, use_sparse_seen_hash, useqq);
     1450                            bless, maxdepth, sortkeys, use_sparse_seen_hash,
     1451                            useqq, maxrecurse);
    14381452                    SPAGAIN;
    14391453               
    14401454                    if (indent >= 2 && !terse)
  • new file dist/Data-Dumper/t/recurse.t

    diff --git a/dist/Data-Dumper/t/recurse.t b/dist/Data-Dumper/t/recurse.t
    new file mode 100644
    index 0000000..275a89d
    - +  
     1#!perl
     2
     3# Test the Maxrecurse option
     4
     5use strict;
     6use Test::More tests => 32;
     7use Data::Dumper;
     8
     9SKIP: {
     10    skip "no XS available", 16
     11      if $Data::Dumper::Useperl;
     12    local $Data::Dumper::Useperl = 1;
     13    test_recursion();
     14}
     15
     16test_recursion();
     17
     18sub test_recursion {
     19    my $pp = $Data::Dumper::Useperl ? "pure perl" : "XS";
     20    $Data::Dumper::Purity = 1; # make sure this has no effect
     21    $Data::Dumper::Indent = 0;
     22    $Data::Dumper::Maxrecurse = 1;
     23    is(eval { Dumper([]) }, '$VAR1 = [];', "$pp: maxrecurse 1, []");
     24    is(eval { Dumper([[]]) }, undef, "$pp: maxrecurse 1, [[]]");
     25    ok($@, "exception thrown");
     26    is(eval { Dumper({}) }, '$VAR1 = {};', "$pp: maxrecurse 1, {}");
     27    is(eval { Dumper({ a => 1 }) }, q($VAR1 = {'a' => 1};),
     28       "$pp: maxrecurse 1, { a => 1 }");
     29    is(eval { Dumper({ a => {} }) }, undef, "$pp: maxrecurse 1, { a => {} }");
     30    ok($@, "exception thrown");
     31    is(eval { Dumper(\1) }, "\$VAR1 = \\1;", "$pp: maxrecurse 1, \\1");
     32    is(eval { Dumper(\\1) }, undef, "$pp: maxrecurse 1, \\1");
     33    ok($@, "exception thrown");
     34    $Data::Dumper::Maxrecurse = 3;
     35    is(eval { Dumper(\1) }, "\$VAR1 = \\1;", "$pp: maxrecurse 3, \\1");
     36    is(eval { Dumper(\(my $s = {})) }, "\$VAR1 = \\{};", "$pp: maxrecurse 3, \\{}");
     37    is(eval { Dumper(\(my $s = { a => [] })) }, "\$VAR1 = \\{'a' => []};",
     38       "$pp: maxrecurse 3, \\{ a => [] }");
     39    is(eval { Dumper(\(my $s = { a => [{}] })) }, undef,
     40       "$pp: maxrecurse 3, \\{ a => [{}] }");
     41    ok($@, "exception thrown");
     42    $Data::Dumper::Maxrecurse = 0;
     43    is(eval { Dumper([[[[[]]]]]) }, q($VAR1 = [[[[[]]]]];),
     44       "$pp: check Maxrecurse doesn't set limit to 0 recursion");
     45}