This is an automated email from the git hooks/post-receive script.

guillem pushed a commit to branch main
in repository dpkg.

View the commit online:
https://git.dpkg.org/cgit/dpkg/dpkg.git/commit/?id=3ec8d6521182b7f76897959694d70283b13ace14

commit 3ec8d6521182b7f76897959694d70283b13ace14
Author: Guillem Jover <[email protected]>
AuthorDate: Tue Mar 28 00:39:57 2023 +0200

    Dpkg::Substvars: Handle exponential expansion gracefully
    
    We should switch our excessive recursive prevention check to cover
    exponential expansion. Because with exponential expansion we always
    make progress, the current check misses those cases, so we track
    expansion per variable, and ignore those variables that do not contain
    any dollar symbol as these cannot then be involved in further expansion.
    
    In this context this is not considered a security issue, but a
    robustness issue, where we do not want the code to end up consuming
    boundless amounts of memory.
---
 scripts/Dpkg/Substvars.pm  | 23 +++++++++++---------
 scripts/t/Dpkg_Substvars.t | 52 +++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 62 insertions(+), 13 deletions(-)

diff --git a/scripts/Dpkg/Substvars.pm b/scripts/Dpkg/Substvars.pm
index d3a1fff72..7cced4d56 100644
--- a/scripts/Dpkg/Substvars.pm
+++ b/scripts/Dpkg/Substvars.pm
@@ -47,6 +47,7 @@ use constant {
     SUBSTVAR_ATTR_AUTO => 2,
     SUBSTVAR_ATTR_AGED => 4,
     SUBSTVAR_ATTR_OPT  => 8,
+    SUBSTVAR_ATTR_DEEP => 16,
 };
 
 =head1 METHODS
@@ -102,6 +103,7 @@ sub set {
     my ($self, $key, $value, $attr) = @_;
 
     $attr //= 0;
+    $attr |= SUBSTVAR_ATTR_DEEP if length $value && $value =~ m{\$};
 
     $self->{vars}{$key} = $value;
     $self->{attr}{$key} = $attr;
@@ -321,29 +323,30 @@ Substitutes variables in $string and return the result in 
$newstring.
 
 sub substvars {
     my ($self, $v, %opts) = @_;
+    my %seen;
     my $lhs;
     my $vn;
     my $rhs = '';
-    my $count = 0;
     $opts{msg_prefix} //= $self->{msg_prefix};
     $opts{no_warn} //= 0;
 
     while ($v =~ m/^(.*?)\$\{([-:0-9a-z]+)\}(.*)$/si) {
-        # If we have consumed more from the leftover data, then
-        # reset the recursive counter.
-        $count = 0 if (length($3) < length($rhs));
-
-        if ($count >= $maxsubsts) {
-            error($opts{msg_prefix} .
-                  g_("too many substitutions - recursive ? - in '%s'"), $v);
-        }
         $lhs = $1;
         $vn = $2;
         $rhs = $3;
+
         if (defined($self->{vars}{$vn})) {
             $v = $lhs . $self->{vars}{$vn} . $rhs;
             $self->mark_as_used($vn);
-            $count++;
+
+            if ($self->{attr}{$vn} & SUBSTVAR_ATTR_DEEP) {
+                $seen{$vn}++;
+            }
+            if (exists $seen{$vn} && $seen{$vn} >= $maxsubsts) {
+                error($opts{msg_prefix} .
+                      g_("too many \${%s} substitutions (recursive?) in '%s'"),
+                      $vn, $v);
+            }
 
             if ($self->{attr}{$vn} & SUBSTVAR_ATTR_AGED) {
                 error($opts{msg_prefix} .
diff --git a/scripts/t/Dpkg_Substvars.t b/scripts/t/Dpkg_Substvars.t
index 92afb76de..61ac0276b 100644
--- a/scripts/t/Dpkg_Substvars.t
+++ b/scripts/t/Dpkg_Substvars.t
@@ -16,7 +16,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 55;
+use Test::More tests => 56;
 use Test::Dpkg qw(:paths);
 
 use Dpkg ();
@@ -171,10 +171,56 @@ eval {
 };
 $output = $@ // q{};
 is($output,
-   'Dpkg_Substvars.t: error: test too many substitutions ' .
-   "- recursive ? - in 'Cycle reference \${ref2}'\n",
+   'Dpkg_Substvars.t: error: test too many ${ref0} substitutions ' .
+   "(recursive?) in 'Cycle reference \${ref1}'\n",
    'recursive cyclic expansion is limited');
 
+# Recursive replace: Billion laughs.
+$s->set('ex0', ':)');
+$s->set('ex1', '${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}');
+$s->set('ex2', '${ex1}${ex1}${ex1}${ex1}${ex1}${ex1}${ex1}${ex1}${ex1}${ex1}');
+$s->set('ex3', '${ex2}${ex2}${ex2}${ex2}${ex2}${ex2}${ex2}${ex2}${ex2}${ex2}');
+$s->set('ex4', '${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}');
+$s->set('ex5', '${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}');
+$s->set('ex6', '${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}');
+$s->set('ex7', '${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}');
+$s->set('ex8', '${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}');
+$s->set('ex9', '${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}');
+
+eval {
+    $s->substvars('Billion laughs ${ex9}');
+    1;
+};
+$output = $@ // q{};
+is($output,
+   'Dpkg_Substvars.t: error: test too many ${ex1} substitutions ' .
+   "(recursive?) in 'Billion laughs :):):):):):):):):):):):):):)" .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   ':):):):):):):):):):):):):):):):):):):):):):):):):):)' .
+   '${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}${ex0}' .
+   '${ex2}${ex2}${ex2}${ex2}${ex2}' .
+   '${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}${ex3}' .
+   '${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}${ex4}' .
+   '${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}${ex5}' .
+   '${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}${ex6}' .
+   '${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}${ex7}' .
+   '${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}${ex8}' .
+   "'\n",
+   'recursive or exponential expansion is limited');
 
 # Strange input
 is($s->substvars('Nothing to $ ${substitute  here}, is it ${}?, it ${is'),

-- 
Dpkg.Org's dpkg

Reply via email to