[packages/rt] - up to 4.4.2; SECURITY fixes

arekm arekm at pld-linux.org
Fri Aug 4 12:36:08 CEST 2017


commit d83a97c7a1b5a9e3df83c8cdd0fdb5550b9178ac
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Fri Aug 4 12:36:01 2017 +0200

    - up to 4.4.2; SECURITY fixes

 rt-4.4.1.patch | 319 ---------------------------------------------------------
 rt.spec        |   8 +-
 2 files changed, 3 insertions(+), 324 deletions(-)
---
diff --git a/rt.spec b/rt.spec
index 29200c5..228b372 100644
--- a/rt.spec
+++ b/rt.spec
@@ -44,12 +44,12 @@
 Summary:	Request Tracker
 Summary(pl.UTF-8):	Request Tracker - system do śledzenia zleceń
 Name:		rt
-Version:	4.4.1
-Release:	2
+Version:	4.4.2
+Release:	1
 License:	GPL v2
 Group:		Applications
 Source0:	http://download.bestpractical.com/pub/rt/release/%{name}-%{version}.tar.gz
-# Source0-md5:	3587522b92a02d3866e07dc9361ca1e2
+# Source0-md5:	ed8ecebd9029e143dfbfdb29036fada8
 Source1:	%{name}-apache_dir.conf
 Source2:	%{name}-apache_vhost.conf
 Source3:	%{name}-apache.conf
@@ -57,7 +57,6 @@ Source4:	%{name}.logrotate
 Source5:	lighttpd.conf
 Patch0:		%{name}-layout.patch
 Patch1:		%{name}-config.patch
-Patch2:		rt-4.4.1.patch
 URL:		http://www.bestpractical.com/rt/
 BuildRequires:	autoconf
 BuildRequires:	automake
@@ -319,7 +318,6 @@ Pliki wspomagające używanie RT z Apache.
 %setup -q
 %patch0 -p0
 %patch1 -p1
-%patch2 -p1
 
 mv aclocal.m4 acinclude.m4
 
diff --git a/rt-4.4.1.patch b/rt-4.4.1.patch
deleted file mode 100644
index 0c237f8..0000000
--- a/rt-4.4.1.patch
+++ /dev/null
@@ -1,319 +0,0 @@
-diff --git a/lib/RT.pm b/lib/RT.pm
-index ccf3c54..80d2b61 100644
---- a/lib/RT.pm
-+++ b/lib/RT.pm
-@@ -81,6 +81,10 @@ use vars qw($BasePath
-  $MasonDataDir
-  $MasonSessionDir);
- 
-+# Set Email::Address module var before anything else loads.
-+# This avoids an algorithmic complexity denial of service vulnerability.
-+# See T#157608 and CVE-2015-7686 for more information.
-+$Email::Address::COMMENT_NEST_LEVEL = 1;
- 
- RT->LoadGeneratedData();
- 
-diff --git a/lib/RT/Authen/ExternalAuth/DBI.pm b/lib/RT/Authen/ExternalAuth/DBI.pm
-index 42a157f..4c7f0f3 100644
---- a/lib/RT/Authen/ExternalAuth/DBI.pm
-+++ b/lib/RT/Authen/ExternalAuth/DBI.pm
-@@ -50,6 +50,7 @@ package RT::Authen::ExternalAuth::DBI;
- 
- use DBI;
- use RT::Authen::ExternalAuth::DBI::Cookie;
-+use RT::Util;
- 
- use warnings;
- use strict;
-@@ -81,6 +82,7 @@ Provides the database implementation for L<RT::Authen::ExternalAuth>.
-             'p_field'                   =>  'password',
- 
-             # Example of custom hashed password check
-+            # (See below for security concerns with this implementation)
-             #'p_check'                   =>  sub {
-             #    my ($hash_from_db, $password) = @_;
-             #    return $hash_from_db eq function($password);
-@@ -170,6 +172,17 @@ An example, where C<FooBar()> is some external hashing function:
- Importantly, the C<p_check> subroutine allows for arbitrarily complex password
- checking unlike C<p_enc_pkg> and C<p_enc_sub>.
- 
-+Please note, the use of the C<eq> operator in the C<p_check> example above
-+introduces a timing sidechannel vulnerability. (It was left there for clarity
-+of the example.) There is a comparison function available in RT that is
-+hardened against timing attacks. The comparison from the above example could
-+be re-written with it like this:
-+
-+    p_check => sub {
-+        my ($hash_from_db, $password) = @_;
-+        return RT::Util::constant_time_eq($hash_from_db, FooBar($password));
-+    },
-+
- =item p_enc_pkg, p_enc_sub
- 
- The Perl package and subroutine used to encrypt passwords from the
-@@ -298,7 +311,7 @@ sub GetAuth {
-         # Jump to the next external authentication service if they don't match
-         if(defined($db_p_salt)) {
-             $RT::Logger->debug("Using salt:",$db_p_salt);
--            if(${encrypt}->($password,$db_p_salt) ne $pass_from_db){
-+            unless (RT::Util::constant_time_eq(${encrypt}->($password,$db_p_salt), $pass_from_db)) {
-                 $RT::Logger->info(  $service,
-                                     "AUTH FAILED",
-                                     $username,
-@@ -306,7 +319,7 @@ sub GetAuth {
-                 return 0;
-             }
-         } else {
--            if(${encrypt}->($password) ne $pass_from_db){
-+            unless (RT::Util::constant_time_eq(${encrypt}->($password), $pass_from_db)) {
-                 $RT::Logger->info(  $service,
-                                     "AUTH FAILED",
-                                     $username,
-diff --git a/lib/RT/Config.pm b/lib/RT/Config.pm
-index 70df38f..81a95f7 100644
---- a/lib/RT/Config.pm
-+++ b/lib/RT/Config.pm
-@@ -147,6 +147,14 @@ can be set for each config optin:
- our %META;
- %META = (
-     # General user overridable options
-+    RestrictReferrerLogin => {
-+        PostLoadCheck => sub {
-+            my $self = shift;
-+            if (defined($self->Get('RestrictReferrerLogin'))) {
-+                RT::Logger->error("The config option 'RestrictReferrerLogin' is incorrect, and should be 'RestrictLoginReferrer' instead.");
-+            }
-+        },
-+    },
-     DefaultQueue => {
-         Section         => 'General',
-         Overridable     => 1,
-diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
-index e3cf905..7f9cf6f 100644
---- a/lib/RT/Interface/Web.pm
-+++ b/lib/RT/Interface/Web.pm
-@@ -1448,7 +1448,7 @@ sub IsCompCSRFWhitelisted {
-     # golden.  This acts on the presumption that external forms may
-     # hardcode a username and password -- if a malicious attacker knew
-     # both already, CSRF is the least of your problems.
--    my $AllowLoginCSRF = not RT->Config->Get('RestrictReferrerLogin');
-+    my $AllowLoginCSRF = not RT->Config->Get('RestrictLoginReferrer');
-     if ($AllowLoginCSRF and defined($args{user}) and defined($args{pass})) {
-         my $user_obj = RT::CurrentUser->new();
-         $user_obj->Load($args{user});
-@@ -1666,7 +1666,7 @@ sub MaybeShowInterstitialCSRFPage {
-     my $token = StoreRequestToken($ARGS);
-     $HTML::Mason::Commands::m->comp(
-         '/Elements/CSRF',
--        OriginalURL => RT->Config->Get('WebPath') . $HTML::Mason::Commands::r->path_info,
-+        OriginalURL => RT->Config->Get('WebBaseURL') . RT->Config->Get('WebPath') . $HTML::Mason::Commands::r->path_info,
-         Reason => HTML::Mason::Commands::loc( $msg, @loc ),
-         Token => $token,
-     );
-diff --git a/lib/RT/User.pm b/lib/RT/User.pm
-index e9ccca8..0e86d44 100644
---- a/lib/RT/User.pm
-+++ b/lib/RT/User.pm
-@@ -84,6 +84,7 @@ use RT::Principals;
- use RT::ACE;
- use RT::Interface::Email;
- use Text::Password::Pronounceable;
-+use RT::Util;
- 
- sub _OverlayAccessible {
-     {
-@@ -1087,11 +1088,17 @@ sub IsPassword {
-         # If it's a new-style (>= RT 4.0) password, it starts with a '!'
-         my (undef, $method, @rest) = split /!/, $stored;
-         if ($method eq "bcrypt") {
--            return 0 unless $self->_GeneratePassword_bcrypt($value, @rest) eq $stored;
-+            return 0 unless RT::Util::constant_time_eq(
-+                $self->_GeneratePassword_bcrypt($value, @rest),
-+                $stored
-+            );
-             # Upgrade to a larger number of rounds if necessary
-             return 1 unless $rest[0] < RT->Config->Get('BcryptCost');
-         } elsif ($method eq "sha512") {
--            return 0 unless $self->_GeneratePassword_sha512($value, @rest) eq $stored;
-+            return 0 unless RT::Util::constant_time_eq(
-+                $self->_GeneratePassword_sha512($value, @rest),
-+                $stored
-+            );
-         } else {
-             $RT::Logger->warn("Unknown hash method $method");
-             return 0;
-@@ -1101,16 +1108,28 @@ sub IsPassword {
-         my $hash = MIME::Base64::decode_base64($stored);
-         # Decoding yields 30 byes; first 4 are the salt, the rest are substr(SHA256,0,26)
-         my $salt = substr($hash, 0, 4, "");
--        return 0 unless substr(Digest::SHA::sha256($salt . Digest::MD5::md5(Encode::encode( "UTF-8", $value))), 0, 26) eq $hash;
-+        return 0 unless RT::Util::constant_time_eq(
-+            substr(Digest::SHA::sha256($salt . Digest::MD5::md5(Encode::encode( "UTF-8", $value))), 0, 26),
-+            $hash
-+        );
-     } elsif (length $stored == 32) {
-         # Hex nonsalted-md5
--        return 0 unless Digest::MD5::md5_hex(Encode::encode( "UTF-8", $value)) eq $stored;
-+        return 0 unless RT::Util::constant_time_eq(
-+            Digest::MD5::md5_hex(Encode::encode( "UTF-8", $value)),
-+            $stored
-+        );
-     } elsif (length $stored == 22) {
-         # Base64 nonsalted-md5
--        return 0 unless Digest::MD5::md5_base64(Encode::encode( "UTF-8", $value)) eq $stored;
-+        return 0 unless RT::Util::constant_time_eq(
-+            Digest::MD5::md5_base64(Encode::encode( "UTF-8", $value)),
-+            $stored
-+        );
-     } elsif (length $stored == 13) {
-         # crypt() output
--        return 0 unless crypt(Encode::encode( "UTF-8", $value), $stored) eq $stored;
-+        return 0 unless RT::Util::constant_time_eq(
-+            crypt(Encode::encode( "UTF-8", $value), $stored),
-+            $stored
-+        );
-     } else {
-         $RT::Logger->warning("Unknown password form");
-         return 0;
-@@ -1206,19 +1225,20 @@ sub GenerateAuthString {
- 
- =head3 ValidateAuthString
- 
--Takes auth string and protected string. Returns true is protected string
-+Takes auth string and protected string. Returns true if protected string
- has been protected by user's L</AuthToken>. See also L</GenerateAuthString>.
- 
- =cut
- 
- sub ValidateAuthString {
-     my $self = shift;
--    my $auth_string = shift;
-+    my $auth_string_to_validate = shift;
-     my $protected = shift;
- 
-     my $str = Encode::encode( "UTF-8", $self->AuthToken . $protected );
-+    my $valid_auth_string = substr(Digest::MD5::md5_hex($str),0,16);
- 
--    return $auth_string eq substr(Digest::MD5::md5_hex($str),0,16);
-+    return RT::Util::constant_time_eq( $auth_string_to_validate, $valid_auth_string );
- }
- 
- =head2 SetDisabled
-diff --git a/lib/RT/Util.pm b/lib/RT/Util.pm
-index 70b557b..47b1dd2 100644
---- a/lib/RT/Util.pm
-+++ b/lib/RT/Util.pm
-@@ -54,6 +54,8 @@ use warnings;
- use base 'Exporter';
- our @EXPORT = qw/safe_run_child mime_recommended_filename/;
- 
-+use Encode qw/encode/;
-+
- sub safe_run_child (&) {
-     my $our_pid = $$;
- 
-@@ -150,6 +152,58 @@ sub assert_bytes {
- }
- 
- 
-+=head2 C<constant_time_eq($a, $b)>
-+
-+Compares two strings for equality in constant-time. Replacement for the C<eq>
-+operator designed to avoid timing side-channel vulnerabilities. Returns zero
-+or one.
-+
-+This is intended for use in cryptographic subsystems for comparing well-formed
-+data such as hashes - not for direct use with user input or as a general
-+replacement for the C<eq> operator.
-+
-+The two string arguments B<MUST> be of equal length. If the lengths differ,
-+this function will call C<die()>, as proceeding with execution would create
-+a timing vulnerability. Length is defined by characters, not bytes.
-+
-+This code has been tested to do what it claims. Do not change it without
-+thorough statistical timing analysis to validate the changes.
-+
-+Added to resolve CVE-2017-5361
-+
-+For more on timing attacks, see this Wikipedia article:
-+B<https://en.wikipedia.org/wiki/Timing_attack>
-+
-+=cut
-+
-+sub constant_time_eq {
-+    my ($a, $b) = @_;
-+
-+    my $result = 0;
-+
-+    # generic error message avoids potential information leaks
-+    my $generic_error = "Cannot compare values";
-+    die $generic_error unless defined $a and defined $b;
-+    die $generic_error unless length $a == length $b;
-+    die $generic_error if ref($a) or ref($b);
-+
-+    for (my $i = 0; $i < length($a); $i++) {
-+        my $a_char = substr($a, $i, 1);
-+        my $b_char = substr($b, $i, 1);
-+
-+        # encode() is set to die on malformed
-+        my @a_octets = unpack("C*", encode('UTF-8', $a_char, Encode::FB_CROAK));
-+        my @b_octets = unpack("C*", encode('UTF-8', $b_char, Encode::FB_CROAK));
-+        die $generic_error if (scalar @a_octets) != (scalar @b_octets);
-+
-+        for (my $j = 0; $j < scalar @a_octets; $j++) {
-+            $result |= $a_octets[$j] ^ $b_octets[$j];
-+        }
-+    }
-+    return 0 + not $result;
-+}
-+
-+
- RT::Base->_ImportOverlays();
- 
- 1;
-diff --git a/sbin/rt-test-dependencies b/sbin/rt-test-dependencies
-index 0e57ca1..07bb082 100644
---- a/sbin/rt-test-dependencies
-+++ b/sbin/rt-test-dependencies
-@@ -136,7 +136,7 @@ Devel::StackTrace 1.19
- Digest::base
- Digest::MD5 2.27
- Digest::SHA
--Email::Address 1.897
-+Email::Address 1.908
- Email::Address::List 0.02
- Encode 2.64
- Errno
-diff --git a/share/html/Dashboards/Subscription.html b/share/html/Dashboards/Subscription.html
-index 34aaa33..36abd2a 100644
---- a/share/html/Dashboards/Subscription.html
-+++ b/share/html/Dashboards/Subscription.html
-@@ -75,7 +75,7 @@
- <ol class="dashboard-queries">
- %    for my $portlet (@portlets) {
-         <li class="dashboard-query">
--            <% loc($portlet->{description}, $fields{'Rows'}) %>
-+            <% loc( RT::SavedSearch->EscapeDescription($portlet->{description}), $fields{'Rows'}) %>
-         </li>
- %    }
- </ol>
-diff --git a/share/html/Ticket/Attachment/dhandler b/share/html/Ticket/Attachment/dhandler
-index 3d7c07b..c6ca376 100644
---- a/share/html/Ticket/Attachment/dhandler
-+++ b/share/html/Ticket/Attachment/dhandler
-@@ -68,11 +68,13 @@ unless ( $AttachmentObj->TransactionId() == $trans ) {
- my $content = $AttachmentObj->OriginalContent;
- my $content_type = $AttachmentObj->ContentType || 'text/plain';
- 
--if ( RT->Config->Get('AlwaysDownloadAttachments') ) {
-+my $attachment_regex = qr{^(image/svg\+xml|application/pdf)}i;
-+if ( RT->Config->Get('AlwaysDownloadAttachments') || ($content_type =~ $attachment_regex) ) {
-     $r->headers_out->{'Content-Disposition'} = "attachment";
- }
- elsif ( !RT->Config->Get('TrustHTMLAttachments') ) {
--    $content_type = 'text/plain' if ( $content_type =~ /^text\/html/i );
-+    my $text_plain_regex = qr{^(text/html|application/xhtml\+xml|text/xml|application/xml)}i;
-+    $content_type = 'text/plain' if ( $content_type =~ $text_plain_regex );
- }
- elsif (lc $content_type eq 'text/html') {
-     # If we're trusting and serving HTML for display not download, try to do
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/rt.git/commitdiff/d83a97c7a1b5a9e3df83c8cdd0fdb5550b9178ac



More information about the pld-cvs-commit mailing list