summaryrefslogtreecommitdiffstats
path: root/debian/patches/80_01-GnuTLS-fix-hanging-callout-connections.patch
blob: 0f36d732153fccf409ada739b43418b9ab6cea45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
From 97c5e07c220b55d1c506a1798c9ce3ae3105adea Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Thu, 13 Feb 2020 16:45:38 +0000
Subject: [PATCH 4/6] GnuTLS: fix hanging callout connections

Broken-by: 925ac8e4f1
(cherry picked from commit bd95ffc2ba87fbd3c752df17bc8fd9c01586d45a)
---
 doc/ChangeLog | 81 ++++---------------------------------------
 src/tls-gnu.c     | 24 +++++++------
 2 files changed, 20 insertions(+), 85 deletions(-)

--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -67,6 +67,11 @@ JH/41 Bug 2571: Fix SPA authenticator.
       being used.  A malicious client could thus cause an out-of-bounds read and
       possibly gain authentication.  Fix by adding the check.
 
+JH/25 Fix use of concurrent TLS connections under GnuTLS.  When a callout was
+      done during a receiving connection, and both used TLS, global info was
+      used rather than per-connection info for tracking the state of data
+      queued for transmission.  This could result in a connection hang.
+
 
 Exim version 4.92
 -----------------
--- a/src/tls-gnu.c
+++ b/src/tls-gnu.c
@@ -124,10 +124,17 @@ typedef struct exim_gnutls_state {
   enum peer_verify_requirement verify_requirement;
   int			fd_in;
   int			fd_out;
-  BOOL			peer_cert_verified;
-  BOOL			peer_dane_verified;
-  BOOL			trigger_sni_changes;
-  BOOL			have_set_peerdn;
+
+  BOOL			peer_cert_verified:1;
+  BOOL			peer_dane_verified:1;
+  BOOL			trigger_sni_changes:1;
+  BOOL			have_set_peerdn:1;
+  BOOL			xfer_eof:1;	/*XXX never gets set! */
+  BOOL			xfer_error:1;
+#ifdef SUPPORT_CORK
+  BOOL			corked:1;
+#endif
+
   const struct host_item *host;		/* NULL if server */
   gnutls_x509_crt_t	peercert;
   uschar		*peerdn;
@@ -160,8 +167,6 @@ typedef struct exim_gnutls_state {
   uschar *xfer_buffer;
   int xfer_buffer_lwm;
   int xfer_buffer_hwm;
-  BOOL xfer_eof;	/*XXX never gets set! */
-  BOOL xfer_error;
 } exim_gnutls_state_st;
 
 static const exim_gnutls_state_st exim_gnutls_state_init = {
@@ -2790,9 +2795,8 @@ ssize_t outbytes;
 size_t left = len;
 exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server;
 #ifdef SUPPORT_CORK
-static BOOL corked = FALSE;
 
-if (more && !corked) gnutls_record_cork(state->session);
+if (more && !state->corked) gnutls_record_cork(state->session);
 #endif
 
 DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__,
@@ -2833,10 +2837,10 @@ if (len > INT_MAX)
   }
 
 #ifdef SUPPORT_CORK
-if (more != corked)
+if (more != state->corked)
   {
   if (!more) (void) gnutls_record_uncork(state->session, 0);
-  corked = more;
+  state->corked = more;
   }
 #endif