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>
| 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 |