summaryrefslogtreecommitdiff
blob: f0fee070deb65b7abf0048883b28624298556c20 (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
Upstream: https://git.savannah.gnu.org/cgit/pspp.git/commit/?id=abd1f816ca3b4f382bddf4564ad092aa934f0ccc
Bug: https://bugs.gentoo.org/679392

From abd1f816ca3b4f382bddf4564ad092aa934f0ccc Mon Sep 17 00:00:00 2001
From: Ben Pfaff <blp@cs.stanford.edu>
Date: Tue, 1 Jan 2019 08:36:05 -0800
Subject: pspp-dump-sav: Issue error message for too-large extension records.

CVE-2018-20230.
---
 NEWS                      |  2 ++
 utilities/pspp-dump-sav.c | 30 ++++++++++++++++++------------
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/NEWS b/NEWS
index 3263062ca..191a9804b 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,8 @@ Changes since 1.2.0:
  * Plain text output is no longer divided into pages, since it is now
    rarely printed on paper.
 
+ * Bug fix for CVE-2018-20230.
+
 Changes from 1.0.1 to 1.2.0:
 
  * New experimental command SAVE DATA COLLECTION to save MDD files.
diff --git a/utilities/pspp-dump-sav.c b/utilities/pspp-dump-sav.c
index aeb648665..b0001ac61 100644
--- a/utilities/pspp-dump-sav.c
+++ b/utilities/pspp-dump-sav.c
@@ -37,6 +37,7 @@
 #include "gl/progname.h"
 #include "gl/version-etc.h"
 #include "gl/xalloc.h"
+#include "gl/xsize.h"
 
 #define ID_MAX_LEN 64
 
@@ -99,7 +100,7 @@ static void read_simple_compressed_data (struct sfm_reader *, int max_cases);
 static void read_zlib_compressed_data (struct sfm_reader *);
 
 static struct text_record *open_text_record (
-  struct sfm_reader *, size_t size);
+  struct sfm_reader *, size_t size, size_t count);
 static void close_text_record (struct text_record *);
 static bool read_variable_to_value_pair (struct text_record *,
                                          char **key, char **value);
@@ -735,7 +736,7 @@ read_extra_product_info (struct sfm_reader *r,
   const char *s;
 
   printf ("%08llx: extra product info\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   s = text_get_all (text);
   print_string (s, strlen (s));
   close_text_record (text);
@@ -749,7 +750,7 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("%08llx: multiple response sets\n",
           (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   for (;;)
     {
       const char *name;
@@ -909,7 +910,7 @@ read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("%08llx: long variable names (short => long)\n",
           (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   while (read_variable_to_value_pair (text, &var, &long_name))
     printf ("\t%s => %s\n", var, long_name);
   close_text_record (text);
@@ -926,7 +927,7 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("%08llx: very long strings (variable => length)\n",
           (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   while (read_variable_to_value_pair (text, &var, &length_s))
     printf ("\t%s => %d\n", var, atoi (length_s));
   close_text_record (text);
@@ -1004,7 +1005,7 @@ read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count)
   struct text_record *text;
 
   printf ("%08llx: datafile attributes\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   read_attributes (r, text, "datafile");
   close_text_record (text);
 }
@@ -1196,7 +1197,7 @@ read_variable_attributes (struct sfm_reader *r, size_t size, size_t count)
   struct text_record *text;
 
   printf ("%08llx: variable attributes\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   for (;;)
     {
       const char *variable = text_tokenize (text, ':');
@@ -1389,18 +1390,23 @@ struct text_record
     size_t pos;                 /* Current position in buffer. */
   };
 
-/* Reads SIZE bytes into a text record for R,
+/* Reads SIZE * COUNT bytes into a text record for R,
    and returns the new text record. */
 static struct text_record *
-open_text_record (struct sfm_reader *r, size_t size)
+open_text_record (struct sfm_reader *r, size_t size, size_t count)
 {
   struct text_record *text = xmalloc (sizeof *text);
-  char *buffer = xmalloc (size + 1);
-  read_bytes (r, buffer, size);
+
+  if (size_overflow_p (xsum (1, xtimes (size, count))))
+    sys_error (r, "Extension record too large.");
+
+  size_t n_bytes = size * count;
+  char *buffer = xmalloc (n_bytes + 1);
+  read_bytes (r, buffer, n_bytes);
   buffer[size] = '\0';
   text->reader = r;
   text->buffer = buffer;
-  text->size = size;
+  text->size = n_bytes;
   text->pos = 0;
   return text;
 }
-- 
cgit v1.2.1