From 4998ef16d97b451d49a097cec597a2ded1561ae5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ralf=20Cors=C3=A9pius?= <corsepiu(a)fedoraproject.org>
Date: Wed, 26 Jul 2017 09:17:30 +0200
Subject: Add 0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch
(RHBZ#1475084). Supposed to address CVE-2016-6127, CVE-2017-5361,
CVE-2017-5943, CVE-2017-5944.
---
...Apply-security-2017-06-15-rt-4.2.13.patch.patch | 282 +++++++++++++++++++++
rt.spec | 13 +-
2 files changed, 293 insertions(+), 2 deletions(-)
create mode 100644 0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch
diff --git a/0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch
b/0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch
new file mode 100644
index 0000000..6586af0
--- /dev/null
+++ b/0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch
@@ -0,0 +1,282 @@
+From a7872c6feecead0f33ffbd80967f52155004ceac Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ralf=20Cors=C3=A9pius?= <corsepiu(a)fedoraproject.org>
+Date: Wed, 26 Jul 2017 09:04:48 +0200
+Subject: [PATCH 6/6] Apply security-2017-06-15/rt-4.2.13.patch
+
+---
+ lib/RT.pm | 4 +++
+ lib/RT/Config.pm | 8 +++++
+ lib/RT/Interface/Web.pm | 4 +--
+ lib/RT/User.pm | 38 +++++++++++++++++------
+ lib/RT/Util.pm | 54 +++++++++++++++++++++++++++++++++
+ sbin/rt-test-dependencies.in | 2 +-
+ share/html/Dashboards/Subscription.html | 2 +-
+ share/html/Ticket/Attachment/dhandler | 6 ++--
+ 8 files changed, 103 insertions(+), 15 deletions(-)
+
+diff --git a/lib/RT.pm b/lib/RT.pm
+index 743863de8..b31fecb68 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/Config.pm b/lib/RT/Config.pm
+index 2ec63f856..aa1758772 100644
+--- a/lib/RT/Config.pm
++++ b/lib/RT/Config.pm
+@@ -143,6 +143,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 cbf10d20e..d91527904 100644
+--- a/lib/RT/Interface/Web.pm
++++ b/lib/RT/Interface/Web.pm
+@@ -1426,7 +1426,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});
+@@ -1642,7 +1642,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 39b81976d..28098bc80 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 {
+ {
+@@ -977,11 +978,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;
+@@ -991,16 +998,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;
+@@ -1096,19 +1115,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 70b557bb9..47b1dd2e3 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.in b/sbin/rt-test-dependencies.in
+index fabbdc194..c3d584abb 100644
+--- a/sbin/rt-test-dependencies.in
++++ b/sbin/rt-test-dependencies.in
+@@ -206,7 +206,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 83680ef00..d98d0205f 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 3d7c07bd7..c6ca37668 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
+--
+2.13.3
+
diff --git a/rt.spec b/rt.spec
index 4d2e621..aa3755e 100644
--- a/rt.spec
+++ b/rt.spec
@@ -39,7 +39,7 @@
Name: rt
Version: 4.2.13
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: Request tracker
Group: Applications/Internet
@@ -60,6 +60,8 @@ Patch2: 0002-Broken-test-dependencies.patch
Patch3: 0003-Use-usr-bin-perl-instead-of-usr-bin-env-perl.patch
Patch4: 0004-Remove-fixperms-font-install.patch
Patch5: 0005-Fix-permissions.patch
+# Extracted from
https://download.bestpractical.com/pub/rt/release/security-2017-06-15.tar.gz
+Patch6: 0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch
BuildArch: noarch
@@ -96,7 +98,8 @@ BuildRequires: perl(Devel::StackTrace) >= 1.19
BuildRequires: perl(Devel::GlobalDestruction)
BuildRequires: perl(Digest::base)
BuildRequires: perl(Digest::MD5) >= 2.27
-BuildRequires: perl(Email::Address)
+# Email::Address < 1.908 is vulnerable to CVE-2015-7686
+BuildRequires: perl(Email::Address) >= 1.908
BuildRequires: perl(Email::Address::List) >= 0.02
BuildRequires: perl(Encode) >= 2.39
BuildRequires: perl(Errno)
@@ -358,6 +361,7 @@ while read a; do b=$(echo "$a" | sed -e
's,\.in$,,'); rm "$b"; done
%patch3 -p1
%patch4 -p1
%patch5 -p1
+%patch6 -p1
# Propagate rpm's directories to config.layout
cat << \EOF >> config.layout
@@ -599,6 +603,11 @@ fi
%endif
%changelog
+* Wed Jul 26 2017 Ralf Corsépius <corsepiu(a)fedoraproject.org> - 4.2.13-2
+- Add 0006-Apply-security-2017-06-15-rt-4.2.13.patch.patch (RHBZ#1475084).
+ Supposed to address CVE-2016-6127, CVE-2017-5361, CVE-2017-5943,
+ CVE-2017-5944.
+
* Thu Jul 28 2016 Ralf Corsépius <corsepiu(a)fedoraproject.org> - 4.2.13-1
- Update to rt-4.2.13.
- Reflect upstream URLs having changed.
--
cgit v1.1
https://src.fedoraproject.org/cgit/rt.git/commit/?h=f24&id=4998ef16d9...