diff options
author | Ricardo Signes <rjbs@cpan.org> | 2011-01-17 17:27:46 -0500 |
---|---|---|
committer | Ricardo Signes <rjbs@cpan.org> | 2011-01-17 17:27:56 -0500 |
commit | b7fa2aca51e582188059315e1845ced0732a44c7 (patch) | |
tree | 0cf31e0a0b851b9d5366eb542c2b5a254fa76b7a | |
parent | 8b2a3ac2993be989122a7b4a7241d2a03db24156 (diff) | |
download | perl-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-- | MANIFEST | 2 | ||||
-rw-r--r-- | cpan/CGI/lib/CGI.pm | 28 | ||||
-rw-r--r-- | cpan/CGI/t/headers.t | 47 | ||||
-rw-r--r-- | cpan/CGI/t/multipart_init.t | 20 |
4 files changed, 90 insertions, 7 deletions
@@ -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"); |