summaryrefslogtreecommitdiffstats
path: root/debian/patches/84_10-CVE-2020-28026-Line-truncation-and-injection-in-spoo.patch
blob: 3864de212157b0217ab0117c04b3c03d6a0c4585 (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
From 327f647a849c3974e7107b5386421b0058c15b29 Mon Sep 17 00:00:00 2001
From: Qualys Security Advisory <qsa@qualys.com>
Date: Sun, 21 Feb 2021 21:17:31 -0800
Subject: [PATCH 10/29] CVE-2020-28026: Line truncation and injection in
 spool_read_header()

This also fixes:

2/ In src/spool_in.c:

 462   while (  (len = Ustrlen(big_buffer)) == big_buffer_size-1
 463         && big_buffer[len-1] != '\n'
 464         )
 465     {   /* buffer not big enough for line; certs make this possible */
 466     uschar * buf;
 467     if (big_buffer_size >= BIG_BUFFER_SIZE*4) goto SPOOL_READ_ERROR;
 468     buf = store_get_perm(big_buffer_size *= 2, FALSE);
 469     memcpy(buf, big_buffer, --len);

The --len in memcpy() chops off a useful byte (we know for sure that
big_buffer[len-1] is not a '\n' because we entered the while loop).
---
 src/spool_in.c | 48 +++++++++++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/src/spool_in.c b/src/spool_in.c
index 2d349778c..dbbcf23ee 100644
--- a/src/spool_in.c
+++ b/src/spool_in.c
@@ -307,6 +307,36 @@ dsn_ret = 0;
 dsn_envid = NULL;
 }
 
+static void *
+fgets_big_buffer(FILE *fp)
+{
+int len = 0;
+
+big_buffer[0] = 0;
+if (Ufgets(big_buffer, big_buffer_size, fp) == NULL) return NULL;
+
+while ((len = Ustrlen(big_buffer)) == big_buffer_size-1
+      && big_buffer[len-1] != '\n')
+  {
+  uschar *newbuffer;
+  int newsize;
+
+  if (big_buffer_size >= BIG_BUFFER_SIZE * 4) return NULL;
+  newsize = big_buffer_size * 2;
+  newbuffer = store_get_perm(newsize);
+  memcpy(newbuffer, big_buffer, len);
+
+  big_buffer = newbuffer;
+  big_buffer_size = newsize;
+  if (Ufgets(big_buffer + len, big_buffer_size - len, fp) == NULL) return NULL;
+  }
+
+if (len <= 0 || big_buffer[len-1] != '\n') return NULL;
+return big_buffer;
+}
+
+
+
 
 /*************************************************
 *             Read spool header file             *
@@ -450,21 +480,9 @@ p = big_buffer + 2;
 for (;;)
   {
   int len;
-  if (Ufgets(big_buffer, big_buffer_size, fp) == NULL) goto SPOOL_READ_ERROR;
+  if (fgets_big_buffer(fp) == NULL) goto SPOOL_READ_ERROR;
   if (big_buffer[0] != '-') break;
-  while (  (len = Ustrlen(big_buffer)) == big_buffer_size-1
-	&& big_buffer[len-1] != '\n'
-	)
-    {	/* buffer not big enough for line; certs make this possible */
-    uschar * buf;
-    if (big_buffer_size >= BIG_BUFFER_SIZE*4) goto SPOOL_READ_ERROR;
-    buf = store_get_perm(big_buffer_size *= 2);
-    memcpy(buf, big_buffer, --len);
-    big_buffer = buf;
-    if (Ufgets(big_buffer+len, big_buffer_size-len, fp) == NULL)
-      goto SPOOL_READ_ERROR;
-    }
-  big_buffer[len-1] = 0;
+  big_buffer[Ustrlen(big_buffer)-1] = 0;
 
   switch(big_buffer[1])
     {
@@ -724,7 +742,7 @@ DEBUG(D_deliver)
 buffer. It contains the count of recipients which follow on separate lines.
 Apply an arbitrary sanity check.*/
 
-if (Ufgets(big_buffer, big_buffer_size, fp) == NULL) goto SPOOL_READ_ERROR;
+if (fgets_big_buffer(fp) == NULL) goto SPOOL_READ_ERROR;
 if (sscanf(CS big_buffer, "%d", &rcount) != 1 || rcount > 16384)
   goto SPOOL_FORMAT_ERROR;
 
-- 
2.30.2