[Rt-commit] rt branch, 4.0/gnupg-decrypt-verify-deadlock, created. rt-4.0.8-240-g9143b1d

Ruslan Zakirov ruz at bestpractical.com
Wed Dec 12 16:15:56 EST 2012


The branch, 4.0/gnupg-decrypt-verify-deadlock has been created
        at  9143b1d1ac70dde62efa7f3987b2ac03305cf2bb (commit)

- Log -----------------------------------------------------------------
commit 9143b1d1ac70dde62efa7f3987b2ac03305cf2bb
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Thu Dec 13 01:07:27 2012 +0400

    stop RT from locking on "large" mails
    
    Recent improvement in search for GnuPG encrypted/signed parts
    introduced a deadlock situation. Happens on mail delivery with
    GnuPG enabled and the mail containing a "large" quoted printable
    or base64 encoded part. Size depends on OS and system
    configuration. Symptoms: web server process hangs doing nothing,
    rt-mailgate times out, no messages in logs.
    
    It is incorrect use of pipe inside one process. After some ammount
    of data, Writer just blocks waiting for reader to fetch it.
    
    The commit in question is 258ec2fb531c83df00afae3f428975b9871e1f68
    that was included into 3.8.15 and 4.0.8rc1.

diff --git a/lib/RT/Crypt/GnuPG.pm b/lib/RT/Crypt/GnuPG.pm
index 2330478..fa3512f 100644
--- a/lib/RT/Crypt/GnuPG.pm
+++ b/lib/RT/Crypt/GnuPG.pm
@@ -905,11 +905,23 @@ sub FindProtectedParts {
         # sense) unnecessarily applies a base64 transfer encoding to PGP
         # mail (whose content is already base64-encoded).
         if ( $entity->bodyhandle->is_encoded and $entity->head->mime_encoding ) {
-            pipe( my ($read_decoded, $write_decoded) );
             my $decoder = MIME::Decoder->new( $entity->head->mime_encoding );
             if ($decoder) {
-                eval { $decoder->decode($io, $write_decoded) };
-                $io = $read_decoded;
+                local $@;
+                eval {
+                    my $buf = '';
+                    open my $fh, '>:raw', \$buf
+                        or die "Couldn't open scalar for writing: $!";
+                    $decoder->decode($io, $fh);
+                    close $fh or die "Couldn't close scalar: $!";
+
+                    open my $fh, '<:raw', \$buf
+                        or die "Couldn't re-open scalar for reading: $!";
+                    $io = $fh;
+                    1;
+                } or do {
+                    $RT::Logger->error("Couldn't decode body: $@");
+                }
             }
         }
 
diff --git a/t/mail/gnupg-incoming.t b/t/mail/gnupg-incoming.t
index f662307..6471033 100644
--- a/t/mail/gnupg-incoming.t
+++ b/t/mail/gnupg-incoming.t
@@ -10,7 +10,7 @@ BEGIN {
 }
 
 use RT::Test::GnuPG
-  tests         => 49,
+  tests         => 52,
   actual_server => 1,
   gnupg_options => {
     passphrase => 'rt-test',
@@ -233,7 +233,6 @@ RT::Test->close_mailgate_ok($mail);
     ok(index($orig->Content, $buf) != -1, 'found original msg');
 }
 
-
 # test for signed mail by other key
 $buf = '';
 
@@ -345,3 +344,29 @@ is(@mail, 1, 'caught outgoing mail.');
     unlike( ($attach ? $attach->Content : ''), qr/really should not be there either/);
 }
 
+
+# test that if it gets base64 transfer-encoded long mail then it doesn't hang
+{
+    local $SIG{ALRM} = sub {
+        ok 0, "timed out, web server is probably in deadlock";
+        exit;
+    };
+    alarm 30;
+    $buf = encode_base64('a'x(250*1024));
+    $mail = RT::Test->open_mailgate_ok($baseurl);
+    print $mail <<"EOF";
+From: recipient\@example.com
+To: general\@$RT::rtname
+Content-transfer-encoding: base64
+Subject: Long not encrypted message for queue
+
+$buf
+EOF
+    RT::Test->close_mailgate_ok($mail);
+    alarm 0;
+
+    my $tick = RT::Test->last_ticket;
+    is( $tick->Subject, 'Long not encrypted message for queue',
+        "Created the ticket"
+    );
+}

-----------------------------------------------------------------------


More information about the Rt-commit mailing list