Author: adsb
Date: 2009-09-10 19:26:37 +0000 (Thu, 10 Sep 2009)
New Revision: 2006

Modified:
   trunk/debian/changelog
   trunk/scripts/uscan.pl
Log:
uscan: Fix regressions introduced by the security fix in the previous
upload.  The parser now correctly keeps track of the last match when /g
is used to avoid infinite loops.  Thanks, Raphael Geissert and Martín
Ferrari.  (Closes: #544931)

Modified: trunk/debian/changelog
===================================================================
--- trunk/debian/changelog      2009-09-10 18:44:25 UTC (rev 2005)
+++ trunk/debian/changelog      2009-09-10 19:26:37 UTC (rev 2006)
@@ -1,5 +1,7 @@
-devscripts (2.10.55) UNRELEASED; urgency=low
+devscripts (2.10.55) UNRELEASED; urgency=high
 
+  * Urgency "high" for security fix fix
+
   [ Ryan Niebur ]
   * uscan: fix a regression from the security fix when the command is
     given parameters. use Text::ParseWords::shellwords to parse the
@@ -12,6 +14,10 @@
     in the description of the BTS_SUPPRESS_ACKS variable.  Thanks, Jakub
     Wilk.  (Closes: #542961)
   * licensecheck: Add missing blank line in POD.  Thanks, Nicolas Francois.
+  * uscan: Fix regressions introduced by the security fix in the previous
+    upload.  The parser now correctly keeps track of the last match when /g
+    is used to avoid infinite loops.  Thanks, Raphael Geissert and Martín
+    Ferrari.  (Closes: #544931)
   * l10n updates; thanks, Nicolas Francois:  (Closes: #545327)
     + Update French manpage translations
     + Fix addendum format for dcontrol in po4a/devscripts-po4a.conf

Modified: trunk/scripts/uscan.pl
===================================================================
--- trunk/scripts/uscan.pl      2009-09-10 18:44:25 UTC (rev 2005)
+++ trunk/scripts/uscan.pl      2009-09-10 19:26:37 UTC (rev 2006)
@@ -1838,7 +1838,7 @@
 
 sub safe_replace($$) {
     my ($in, $pat) = @_;
-    $pat =~ s/^\s*(.*)\s*$/$1/;
+    $pat =~ s/^\s*(.*?)\s*$/$1/;
 
     $pat =~ /^(s|tr|y)(.)/;
     my ($op, $sep) = ($1, $2 || '');
@@ -1880,7 +1880,12 @@
        my $global = ($flags =~ s/g//);
        $flags = "(?$flags)" if length $flags;
 
-       my (@captures, $first, $last);
+       my $slashg;
+       if ($regexp =~ /(?<!\\)(\\\\)*\\G/) {
+           $slashg = 1;
+           # if it's not initial, it is too dangerous
+           return 0 if $regexp =~ /^.*[^\\](\\\\)*\\G/;
+       }
 
        # Behave like Perl and treat e.g. "\." in replacement as "."
        # We allow the case escape characters to remain and
@@ -1901,24 +1906,50 @@
        # the global flag was set on the input pattern.
        my $orig_replacement = $replacement;
 
+       my ($first, $last, $pos, $zerowidth, $matched, @captures) = (0, -1, 0);
        while (1) {
            eval {
                # handle errors due to unsafe constructs in $regexp
                no re 'eval';
 
-               my $re = qr/$flags$regexp/;
+               # restore position
+               pos($$in) = $pos if $pos;
 
-               @captures = ($$in =~ $re);
-               ($first, $last) = ($-[0], $+[0]);
+               if ($zerowidth) {
+                   # previous match was a zero-width match, simulate it to set
+                   # the internal flag that avoids the infinite loop
+                   $$in =~ /()/g;
+               }
+               # Need to use /g to make it use and save pos()
+               $matched = ($$in =~ /$flags$regexp/g);
+
+               if ($matched) {
+                   # save position and size of the match
+                   my $oldpos = $pos;
+                   $pos = pos($$in);
+                   ($first, $last) = ($-[0], $+[0]);
+
+                   if ($slashg) {
+                       # \G in the match, weird things can happen
+                       $zerowidth = ($pos == $oldpos);
+                       # For example, matching without a match
+                       $matched = 0 if (not defined $first
+                           or not defined $last);
+                   } else {
+                       $zerowidth = ($last - $first == 0);
+                   }
+                   for my $i (0..$#-) {
+                       $captures[$i] = substr $$in, $-[$i], $+[$i] - $-[$i];
+                   }
+               }
            };
            return 0 if $@;
 
            # No match; leave the original string  untouched but return
            # success as there was nothing wrong with the pattern
-           return 1 if @captures == 0;
+           return 1 unless $matched;
 
            # Replace $X
-           unshift @captures, substr $$in, $first, $last - $first;
            $replacement =~ s/[\$\\](\d)/defined $captures[$1] ? $captures[$1] 
: ''/ge;
            $replacement =~ s/\$\{(\d)\}/defined $captures[$1] ? $captures[$1] 
: ''/ge;
            $replacement =~ s/\$&/$captures[0]/g;
@@ -1931,6 +1962,8 @@
 
            # Actually do the replacement
            substr $$in, $first, $last - $first, $replacement;
+           # Update position
+           $pos += length($replacement) - ($last - $first);
 
            if ($global) {
                $replacement = $orig_replacement;



-- 
To unsubscribe, send mail to pkg-devscripts-unsubscr...@teams.debian.net.

Reply via email to