summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRicardo Signes <rjbs@cpan.org>2011-01-17 17:27:46 -0500
committerRicardo Signes <rjbs@cpan.org>2011-01-17 17:27:56 -0500
commitb7fa2aca51e582188059315e1845ced0732a44c7 (patch)
tree0cf31e0a0b851b9d5366eb542c2b5a254fa76b7a
parent8b2a3ac2993be989122a7b4a7241d2a03db24156 (diff)
downloadperl-b7fa2aca51e582188059315e1845ced0732a44c7.tar.gz
fixes for CVE-2010-4410 and CVE-2010-4411
based on CGI 3.50, patches supplied by Nino Tyni of Debian http://markmail.org/message/f3onn6dkkcswlsui
-rw-r--r--MANIFEST2
-rw-r--r--cpan/CGI/lib/CGI.pm28
-rw-r--r--cpan/CGI/t/headers.t47
-rw-r--r--cpan/CGI/t/multipart_init.t20
4 files changed, 90 insertions, 7 deletions
diff --git a/MANIFEST b/MANIFEST
index 8124e62206..492746d196 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -204,11 +204,13 @@ cpan/CGI/t/Dump.t See if CGI->Dump works
cpan/CGI/t/end_form.t See if CGI.pm works
cpan/CGI/t/form.t See if CGI.pm works
cpan/CGI/t/function.t See if CGI.pm works
+cpan/CGI/t/headers.t See if CGI.pm works
cpan/CGI/t/hidden.t See if CGI.pm works
cpan/CGI/t/html.t See if CGI.pm works
cpan/CGI/t/http.t See if CGI.pm works
cpan/CGI/t/init.t See if CGI.pm works
cpan/CGI/t/init_test.txt See if CGI.pm works
+cpan/CGI/t/multipart_init.t See if CGI.pm works
cpan/CGI/t/no_tabindex.t See if CGI.pm works
cpan/CGI/t/popup_menu.t See if CGI pop menus work
cpan/CGI/t/pretty.t See if CGI.pm works
diff --git a/cpan/CGI/lib/CGI.pm b/cpan/CGI/lib/CGI.pm
index 355b8d1805..1f195606c1 100644
--- a/cpan/CGI/lib/CGI.pm
+++ b/cpan/CGI/lib/CGI.pm
@@ -1457,7 +1457,14 @@ END_OF_FUNC
sub multipart_init {
my($self,@p) = self_or_default(@_);
my($boundary,@other) = rearrange_header([BOUNDARY],@p);
- $boundary = $boundary || '------- =_aaaaaaaaaa0';
+ if (!$boundary) {
+ $boundary = '------- =_';
+ my @chrs = ('0'..'9', 'A'..'Z', 'a'..'z');
+ for (1..17) {
+ $boundary .= $chrs[rand(scalar @chrs)];
+ }
+ }
+
$self->{'separator'} = "$CRLF--$boundary$CRLF";
$self->{'final_separator'} = "$CRLF--$boundary--$CRLF";
$type = SERVER_PUSH($boundary);
@@ -1545,12 +1552,19 @@ sub header {
# CR escaping for values, per RFC 822
for my $header ($type,$status,$cookie,$target,$expires,$nph,$charset,$attachment,$p3p,@other) {
if (defined $header) {
- $header =~ s/
- (?<=\n) # For any character proceeded by a newline
- (?=\S) # ... that is not whitespace
- / /xg; # ... inject a leading space in the new line
- }
- }
+ # From RFC 822:
+ # Unfolding is accomplished by regarding CRLF immediately
+ # followed by a LWSP-char as equivalent to the LWSP-char.
+ $header =~ s/$CRLF(\s)/$1/g;
+
+ # All other uses of newlines are invalid input.
+ if ($header =~ m/$CRLF|\015|\012/) {
+ # shorten very long values in the diagnostic
+ $header = substr($header,0,72).'...' if (length $header > 72);
+ die "Invalid header value contains a newline not followed by whitespace: $header";
+ }
+ }
+ }
$nph ||= $NPH;
diff --git a/cpan/CGI/t/headers.t b/cpan/CGI/t/headers.t
new file mode 100644
index 0000000000..661b74bb79
--- /dev/null
+++ b/cpan/CGI/t/headers.t
@@ -0,0 +1,47 @@
+
+# Test that header generation is spec compliant.
+# References:
+# http://www.w3.org/Protocols/rfc2616/rfc2616.html
+# http://www.w3.org/Protocols/rfc822/3_Lexical.html
+
+use strict;
+use warnings;
+
+use Test::More 'no_plan';
+
+use CGI;
+
+my $cgi = CGI->new;
+
+like $cgi->header( -type => "text/html" ),
+ qr#Type: text/html#, 'known header, basic case: type => "text/html"';
+
+eval { $cgi->header( -type => "text/html".$CGI::CRLF."evil: stuff" ) };
+like($@,qr/contains a newline/,'invalid header blows up');
+
+like $cgi->header( -type => "text/html".$CGI::CRLF." evil: stuff " ),
+ qr#Content-Type: text/html evil: stuff#, 'known header, with leading and trailing whitespace on the continuation line';
+
+eval { $cgi->header( -foobar => "text/html".$CGI::CRLF."evil: stuff" ) };
+like($@,qr/contains a newline/,'unknown header with CRLF embedded blows up');
+
+eval { $cgi->header( -foobar => $CGI::CRLF."Content-type: evil/header" ) };
+like($@,qr/contains a newline/, 'unknown header with leading newlines blows up');
+
+eval { $cgi->redirect( -type => "text/html".$CGI::CRLF."evil: stuff" ) };
+like($@,qr/contains a newline/,'redirect with known header with CRLF embedded blows up');
+
+eval { $cgi->redirect( -foobar => "text/html".$CGI::CRLF."evil: stuff" ) };
+like($@,qr/contains a newline/,'redirect with unknown header with CRLF embedded blows up');
+
+eval { $cgi->redirect( $CGI::CRLF.$CGI::CRLF."Content-Type: text/html") };
+like($@,qr/contains a newline/,'redirect with leading newlines blows up');
+
+{
+ my $cgi = CGI->new('t=bogus%0A%0A<html>');
+ my $out;
+ eval { $out = $cgi->redirect( $cgi->param('t') ) };
+ like($@,qr/contains a newline/, "redirect does not allow double-newline injection");
+}
+
+
diff --git a/cpan/CGI/t/multipart_init.t b/cpan/CGI/t/multipart_init.t
new file mode 100644
index 0000000000..f0a05e08d0
--- /dev/null
+++ b/cpan/CGI/t/multipart_init.t
@@ -0,0 +1,20 @@
+use Test::More 'no_plan';
+
+use CGI;
+
+my $q = CGI->new;
+
+my $sv = $q->multipart_init;
+like( $sv, qr|Content-Type: multipart/x-mixed-replace;boundary="------- =|, 'multipart_init(), basic');
+
+like( $sv, qr/$CGI::CRLF$/, 'multipart_init(), ends in CRLF' );
+
+$sv = $q->multipart_init( 'this_is_the_boundary' );
+like( $sv, qr/boundary="this_is_the_boundary"/, 'multipart_init("simple_boundary")' );
+$sv = $q->multipart_init( -boundary => 'this_is_another_boundary' );
+like($sv,
+ qr/boundary="this_is_another_boundary"/, "multipart_init( -boundary => 'this_is_another_boundary')");
+
+$sv = $q->multipart_init;
+my $sv2 = $q->multipart_init;
+isnt($sv,$sv2,"due to random boundaries, multiple calls produce different results");