summaryrefslogtreecommitdiffstats
path: root/debian/patches/84_22-CVE-2020-28019-Failure-to-reset-function-pointer-aft.patch
blob: 0d442936c656352f2fc22731f537197273dd8bb0 (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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
From 1663ab541b37675dec5bcf235605568ff36ac65a Mon Sep 17 00:00:00 2001
From: Qualys Security Advisory <qsa@qualys.com>
Date: Sun, 21 Feb 2021 22:36:10 -0800
Subject: [PATCH 22/29] CVE-2020-28019: Failure to reset function pointer after
 BDAT error

Based on Phil Pennock's commits 4715403e and 151ffd72, and Jeremy
Harris's commits aa171254 and 9aceb5c2.
---
 src/globals.c |  1 +
 src/globals.h |  1 +
 src/smtp_in.c | 55 +++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/src/globals.c b/src/globals.c
index b3362a34c..894b8487b 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -247,6 +247,7 @@ struct global_flags f =
 	.authentication_local   = FALSE,
 
 	.background_daemon      = TRUE,
+	.bdat_readers_wanted    = FALSE,
 
 	.chunking_offered       = FALSE,
 	.config_changed         = FALSE,
diff --git a/src/globals.h b/src/globals.h
index f71f104e2..58f7ae55f 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -173,6 +173,7 @@ extern struct global_flags {
  BOOL   authentication_local		:1; /* TRUE if non-smtp (implicit authentication) */
 
  BOOL   background_daemon		:1; /* Set FALSE to keep in foreground */
+ BOOL   bdat_readers_wanted		:1; /* BDAT-handling to be pushed on readfunc stack */
 
  BOOL   chunking_offered		:1;
  BOOL   config_changed			:1; /* True if -C used */
diff --git a/src/smtp_in.c b/src/smtp_in.c
index 1a5fbfea3..016c44c0f 100644
--- a/src/smtp_in.c
+++ b/src/smtp_in.c
@@ -602,6 +602,10 @@ if (n > 0)
 #endif
 }
 
+/* Forward declarations */
+static inline void bdat_push_receive_functions(void);
+static inline void bdat_pop_receive_functions(void);
+
 
 /* Get a byte from the smtp input, in CHUNKING mode.  Handle ack of the
 previous BDAT chunk and getting new ones when we run out.  Uses the
@@ -634,9 +638,7 @@ for(;;)
   if (chunking_data_left > 0)
     return lwr_receive_getc(chunking_data_left--);
 
-  receive_getc = lwr_receive_getc;
-  receive_getbuf = lwr_receive_getbuf;
-  receive_ungetc = lwr_receive_ungetc;
+  bdat_pop_receive_functions();
 #ifndef DISABLE_DKIM
   dkim_save = dkim_collect_input;
   dkim_collect_input = 0;
@@ -740,9 +742,7 @@ next_cmd:
 	  goto repeat_until_rset;
 	  }
 
-      receive_getc = bdat_getc;
-      receive_getbuf = bdat_getbuf;	/* r~getbuf is never actually used */
-      receive_ungetc = bdat_ungetc;
+      bdat_push_receive_functions();
 #ifndef DISABLE_DKIM
       dkim_collect_input = dkim_save;
 #endif
@@ -775,9 +775,7 @@ while (chunking_data_left)
   if (!bdat_getbuf(&n)) break;
   }
 
-receive_getc = lwr_receive_getc;
-receive_getbuf = lwr_receive_getbuf;
-receive_ungetc = lwr_receive_ungetc;
+bdat_pop_receive_functions();
 
 if (chunking_state != CHUNKING_LAST)
   {
@@ -787,6 +785,45 @@ if (chunking_state != CHUNKING_LAST)
 }
 
 
+static inline void
+bdat_push_receive_functions(void)
+{
+/* push the current receive_* function on the "stack", and
+replace them by bdat_getc(), which in turn will use the lwr_receive_*
+functions to do the dirty work. */
+if (lwr_receive_getc == NULL)
+  {
+  lwr_receive_getc = receive_getc;
+  lwr_receive_getbuf = receive_getbuf;
+  lwr_receive_ungetc = receive_ungetc;
+  }
+else
+  {
+  DEBUG(D_receive) debug_printf("chunking double-push receive functions\n");
+  }
+
+receive_getc = bdat_getc;
+receive_getbuf = bdat_getbuf;
+receive_ungetc = bdat_ungetc;
+}
+
+static inline void
+bdat_pop_receive_functions(void)
+{
+if (lwr_receive_getc == NULL)
+  {
+  DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n");
+  return;
+  }
+
+receive_getc = lwr_receive_getc;
+receive_getbuf = lwr_receive_getbuf;
+receive_ungetc = lwr_receive_ungetc;
+
+lwr_receive_getc = NULL;
+lwr_receive_getbuf = NULL;
+lwr_receive_ungetc = NULL;
+}
 
 
 /*************************************************
-- 
2.30.2