Browse code

CVE-2018-20406 - python3

Fix for CVE-2018-20406

Change-Id: Id2d376208ee5136cf696484ed4ce2b0440f6b791
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/6672
Tested-by: michellew <michellew@vmware.com>
Reviewed-by: Srinidhi Rao <srinidhir@vmware.com>
Reviewed-by: Anish Swaminathan <anishs@vmware.com>

Tapas Kundu authored on 2019/02/12 07:48:28
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,195 @@
0
+commit a4ae828ee416a66d8c7bf5ee71d653c2cc6a26dd
1
+Author: Benjamin Peterson <benjamin@python.org>
2
+Date:   Thu Sep 20 18:36:40 2018 -0700
3
+
4
+    closes bpo-34656: Avoid relying on signed overflow in _pickle memos. (GH-9261)
5
+
6
+diff --git a/Modules/_pickle.c b/Modules/_pickle.c
7
+index 2de70f5..3588e33 100644
8
+--- a/Modules/_pickle.c
9
+@@ -602,9 +602,9 @@ typedef struct {
10
+ } PyMemoEntry;
11
+ 
12
+ typedef struct {
13
+-    Py_ssize_t mt_mask;
14
+-    Py_ssize_t mt_used;
15
+-    Py_ssize_t mt_allocated;
16
++    size_t mt_mask;
17
++    size_t mt_used;
18
++    size_t mt_allocated;
19
+     PyMemoEntry *mt_table;
20
+ } PyMemoTable;
21
+ 
22
+@@ -650,8 +650,8 @@ typedef struct UnpicklerObject {
23
+     /* The unpickler memo is just an array of PyObject *s. Using a dict
24
+        is unnecessary, since the keys are contiguous ints. */
25
+     PyObject **memo;
26
+-    Py_ssize_t memo_size;       /* Capacity of the memo array */
27
+-    Py_ssize_t memo_len;        /* Number of objects in the memo */
28
++    size_t memo_size;       /* Capacity of the memo array */
29
++    size_t memo_len;        /* Number of objects in the memo */
30
+ 
31
+     PyObject *pers_func;        /* persistent_load() method, can be NULL. */
32
+     PyObject *pers_func_self;   /* borrowed reference to self if pers_func
33
+@@ -737,7 +737,6 @@ PyMemoTable_New(void)
34
+ static PyMemoTable *
35
+ PyMemoTable_Copy(PyMemoTable *self)
36
+ {
37
+-    Py_ssize_t i;
38
+     PyMemoTable *new = PyMemoTable_New();
39
+     if (new == NULL)
40
+         return NULL;
41
+@@ -754,7 +753,7 @@ PyMemoTable_Copy(PyMemoTable *self)
42
+         PyErr_NoMemory();
43
+         return NULL;
44
+     }
45
+-    for (i = 0; i < self->mt_allocated; i++) {
46
++    for (size_t i = 0; i < self->mt_allocated; i++) {
47
+         Py_XINCREF(self->mt_table[i].me_key);
48
+     }
49
+     memcpy(new->mt_table, self->mt_table,
50
+@@ -800,7 +799,7 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
51
+ {
52
+     size_t i;
53
+     size_t perturb;
54
+-    size_t mask = (size_t)self->mt_mask;
55
++    size_t mask = self->mt_mask;
56
+     PyMemoEntry *table = self->mt_table;
57
+     PyMemoEntry *entry;
58
+     Py_hash_t hash = (Py_hash_t)key >> 3;
59
+@@ -821,22 +820,24 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
60
+ 
61
+ /* Returns -1 on failure, 0 on success. */
62
+ static int
63
+-_PyMemoTable_ResizeTable(PyMemoTable *self, Py_ssize_t min_size)
64
++_PyMemoTable_ResizeTable(PyMemoTable *self, size_t min_size)
65
+ {
66
+     PyMemoEntry *oldtable = NULL;
67
+     PyMemoEntry *oldentry, *newentry;
68
+-    Py_ssize_t new_size = MT_MINSIZE;
69
+-    Py_ssize_t to_process;
70
++    size_t new_size = MT_MINSIZE;
71
++    size_t to_process;
72
+ 
73
+     assert(min_size > 0);
74
+ 
75
+-    /* Find the smallest valid table size >= min_size. */
76
+-    while (new_size < min_size && new_size > 0)
77
+-        new_size <<= 1;
78
+-    if (new_size <= 0) {
79
++    if (min_size > PY_SSIZE_T_MAX) {
80
+         PyErr_NoMemory();
81
+         return -1;
82
+     }
83
++
84
++    /* Find the smallest valid table size >= min_size. */
85
++    while (new_size < min_size) {
86
++        new_size <<= 1;
87
++    }
88
+     /* new_size needs to be a power of two. */
89
+     assert((new_size & (new_size - 1)) == 0);
90
+ 
91
+@@ -909,10 +910,12 @@ PyMemoTable_Set(PyMemoTable *self, PyObject *key, Py_ssize_t value)
92
+      * Very large memo tables (over 50K items) use doubling instead.
93
+      * This may help applications with severe memory constraints.
94
+      */
95
+-    if (!(self->mt_used * 3 >= (self->mt_mask + 1) * 2))
96
++    if (SIZE_MAX / 3 >= self->mt_used && self->mt_used * 3 < self->mt_allocated * 2) {
97
+         return 0;
98
+-    return _PyMemoTable_ResizeTable(self,
99
+-        (self->mt_used > 50000 ? 2 : 4) * self->mt_used);
100
++    }
101
++    // self->mt_used is always < PY_SSIZE_T_MAX, so this can't overflow.
102
++    size_t desired_size = (self->mt_used > 50000 ? 2 : 4) * self->mt_used;
103
++    return _PyMemoTable_ResizeTable(self, desired_size);
104
+ }
105
+ 
106
+ #undef MT_MINSIZE
107
+@@ -1376,9 +1379,9 @@ _Unpickler_Readline(UnpicklerObject *self, char **result)
108
+ /* Returns -1 (with an exception set) on failure, 0 on success. The memo array
109
+    will be modified in place. */
110
+ static int
111
+-_Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
112
++_Unpickler_ResizeMemoList(UnpicklerObject *self, size_t new_size)
113
+ {
114
+-    Py_ssize_t i;
115
++    size_t i;
116
+ 
117
+     assert(new_size > self->memo_size);
118
+ 
119
+@@ -1397,9 +1400,9 @@ _Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
120
+ 
121
+ /* Returns NULL if idx is out of bounds. */
122
+ static PyObject *
123
+-_Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
124
++_Unpickler_MemoGet(UnpicklerObject *self, size_t idx)
125
+ {
126
+-    if (idx < 0 || idx >= self->memo_size)
127
++    if (idx >= self->memo_size)
128
+         return NULL;
129
+ 
130
+     return self->memo[idx];
131
+@@ -1408,7 +1411,7 @@ _Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
132
+ /* Returns -1 (with an exception set) on failure, 0 on success.
133
+    This takes its own reference to `value`. */
134
+ static int
135
+-_Unpickler_MemoPut(UnpicklerObject *self, Py_ssize_t idx, PyObject *value)
136
++_Unpickler_MemoPut(UnpicklerObject *self, size_t idx, PyObject *value)
137
+ {
138
+     PyObject *old_item;
139
+ 
140
+@@ -4413,14 +4416,13 @@ static PyObject *
141
+ _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self)
142
+ /*[clinic end generated code: output=bb83a919d29225ef input=b73043485ac30b36]*/
143
+ {
144
+-    Py_ssize_t i;
145
+     PyMemoTable *memo;
146
+     PyObject *new_memo = PyDict_New();
147
+     if (new_memo == NULL)
148
+         return NULL;
149
+ 
150
+     memo = self->pickler->memo;
151
+-    for (i = 0; i < memo->mt_allocated; ++i) {
152
++    for (size_t i = 0; i < memo->mt_allocated; ++i) {
153
+         PyMemoEntry entry = memo->mt_table[i];
154
+         if (entry.me_key != NULL) {
155
+             int status;
156
+@@ -6843,7 +6845,7 @@ static PyObject *
157
+ _pickle_UnpicklerMemoProxy_copy_impl(UnpicklerMemoProxyObject *self)
158
+ /*[clinic end generated code: output=e12af7e9bc1e4c77 input=97769247ce032c1d]*/
159
+ {
160
+-    Py_ssize_t i;
161
++    size_t i;
162
+     PyObject *new_memo = PyDict_New();
163
+     if (new_memo == NULL)
164
+         return NULL;
165
+@@ -6994,8 +6996,7 @@ static int
166
+ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
167
+ {
168
+     PyObject **new_memo;
169
+-    Py_ssize_t new_memo_size = 0;
170
+-    Py_ssize_t i;
171
++    size_t new_memo_size = 0;
172
+ 
173
+     if (obj == NULL) {
174
+         PyErr_SetString(PyExc_TypeError,
175
+@@ -7012,7 +7013,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
176
+         if (new_memo == NULL)
177
+             return -1;
178
+ 
179
+-        for (i = 0; i < new_memo_size; i++) {
180
++        for (size_t i = 0; i < new_memo_size; i++) {
181
+             Py_XINCREF(unpickler->memo[i]);
182
+             new_memo[i] = unpickler->memo[i];
183
+         }
184
+@@ -7060,8 +7061,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
185
+ 
186
+   error:
187
+     if (new_memo_size) {
188
+-        i = new_memo_size;
189
+-        while (--i >= 0) {
190
++        for (size_t i = new_memo_size - 1; i != SIZE_MAX; i--) {
191
+             Py_XDECREF(new_memo[i]);
192
+         }
193
+         PyMem_FREE(new_memo);
... ...
@@ -1,7 +1,7 @@
1 1
 Summary:        A high-level scripting language
2 2
 Name:           python3
3 3
 Version:        3.6.5
4
-Release:        3%{?dist}
4
+Release:        4%{?dist}
5 5
 License:        PSF
6 6
 URL:            http://www.python.org/
7 7
 Group:          System Environment/Programming
... ...
@@ -13,6 +13,7 @@ Patch0:         cgi3.patch
13 13
 Patch1:         python3-support-photon-platform.patch
14 14
 Patch2:         python3-CVE-2017-18207.patch
15 15
 Patch3:         python3-CVE-2018-14647.patch
16
+Patch4:         python3-CVE-2018-20406.patch
16 17
 BuildRequires:  pkg-config >= 0.28
17 18
 BuildRequires:  bzip2-devel
18 19
 BuildRequires:  ncurses-devel
... ...
@@ -136,6 +137,7 @@ The test package contains all regression tests for Python as well as the modules
136 136
 %patch1 -p1
137 137
 %patch2 -p1
138 138
 %patch3 -p1
139
+%patch4 -p1
139 140
 
140 141
 
141 142
 %build
... ...
@@ -266,6 +268,8 @@ rm -rf %{buildroot}/*
266 266
 %{_libdir}/python3.6/test/*
267 267
 
268 268
 %changelog
269
+*   Mon Feb 11 2019 Tapas Kundu <tkundu@vmware.com> 3.6.5-4
270
+-   Fix for CVE-2018-20406
269 271
 *   Mon Dec 31 2018 Tapas Kundu <tkundu@vmware.com> 3.6.5-3
270 272
 -   Fix for CVE-2018-14647
271 273
 *   Thu Oct 25 2018 Sujay g <gsujay@vmware.com> 3.6.5-2