CVE-2018-20406.patch 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. From 3c7fd2b2729e3ebcf7877e7a32b3bbabf907a38d Mon Sep 17 00:00:00 2001
  2. From: Victor Stinner <vstinner@redhat.com>
  3. Date: Tue, 26 Feb 2019 01:42:39 +0100
  4. Subject: [PATCH] closes bpo-34656: Avoid relying on signed overflow in _pickle
  5. memos. (GH-9261) (#11869)
  6. (cherry picked from commit a4ae828ee416a66d8c7bf5ee71d653c2cc6a26dd)
  7. CVE: CVE-2018-20406
  8. Upstream-Status: Backport
  9. [https://github.com/python/cpython/commit/ef33dd6036aafbd3f06c1d56e2b1a81dae3da63c]
  10. Signed-off-by: Dan Tran <dantran@microsoft.com>
  11. ---
  12. Modules/_pickle.c | 63 ++++++++++++++++++++++++-----------------------
  13. 1 file changed, 32 insertions(+), 31 deletions(-)
  14. diff --git a/Modules/_pickle.c b/Modules/_pickle.c
  15. index 0f62b1c019..fcb9e87899 100644
  16. --- a/Modules/_pickle.c
  17. +++ b/Modules/_pickle.c
  18. @@ -527,9 +527,9 @@ typedef struct {
  19. } PyMemoEntry;
  20. typedef struct {
  21. - Py_ssize_t mt_mask;
  22. - Py_ssize_t mt_used;
  23. - Py_ssize_t mt_allocated;
  24. + size_t mt_mask;
  25. + size_t mt_used;
  26. + size_t mt_allocated;
  27. PyMemoEntry *mt_table;
  28. } PyMemoTable;
  29. @@ -573,8 +573,8 @@ typedef struct UnpicklerObject {
  30. /* The unpickler memo is just an array of PyObject *s. Using a dict
  31. is unnecessary, since the keys are contiguous ints. */
  32. PyObject **memo;
  33. - Py_ssize_t memo_size; /* Capacity of the memo array */
  34. - Py_ssize_t memo_len; /* Number of objects in the memo */
  35. + size_t memo_size; /* Capacity of the memo array */
  36. + size_t memo_len; /* Number of objects in the memo */
  37. PyObject *pers_func; /* persistent_load() method, can be NULL. */
  38. @@ -658,7 +658,6 @@ PyMemoTable_New(void)
  39. static PyMemoTable *
  40. PyMemoTable_Copy(PyMemoTable *self)
  41. {
  42. - Py_ssize_t i;
  43. PyMemoTable *new = PyMemoTable_New();
  44. if (new == NULL)
  45. return NULL;
  46. @@ -675,7 +674,7 @@ PyMemoTable_Copy(PyMemoTable *self)
  47. PyErr_NoMemory();
  48. return NULL;
  49. }
  50. - for (i = 0; i < self->mt_allocated; i++) {
  51. + for (size_t i = 0; i < self->mt_allocated; i++) {
  52. Py_XINCREF(self->mt_table[i].me_key);
  53. }
  54. memcpy(new->mt_table, self->mt_table,
  55. @@ -721,7 +720,7 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
  56. {
  57. size_t i;
  58. size_t perturb;
  59. - size_t mask = (size_t)self->mt_mask;
  60. + size_t mask = self->mt_mask;
  61. PyMemoEntry *table = self->mt_table;
  62. PyMemoEntry *entry;
  63. Py_hash_t hash = (Py_hash_t)key >> 3;
  64. @@ -743,22 +742,24 @@ _PyMemoTable_Lookup(PyMemoTable *self, PyObject *key)
  65. /* Returns -1 on failure, 0 on success. */
  66. static int
  67. -_PyMemoTable_ResizeTable(PyMemoTable *self, Py_ssize_t min_size)
  68. +_PyMemoTable_ResizeTable(PyMemoTable *self, size_t min_size)
  69. {
  70. PyMemoEntry *oldtable = NULL;
  71. PyMemoEntry *oldentry, *newentry;
  72. - Py_ssize_t new_size = MT_MINSIZE;
  73. - Py_ssize_t to_process;
  74. + size_t new_size = MT_MINSIZE;
  75. + size_t to_process;
  76. assert(min_size > 0);
  77. - /* Find the smallest valid table size >= min_size. */
  78. - while (new_size < min_size && new_size > 0)
  79. - new_size <<= 1;
  80. - if (new_size <= 0) {
  81. + if (min_size > PY_SSIZE_T_MAX) {
  82. PyErr_NoMemory();
  83. return -1;
  84. }
  85. +
  86. + /* Find the smallest valid table size >= min_size. */
  87. + while (new_size < min_size) {
  88. + new_size <<= 1;
  89. + }
  90. /* new_size needs to be a power of two. */
  91. assert((new_size & (new_size - 1)) == 0);
  92. @@ -808,6 +809,7 @@ static int
  93. PyMemoTable_Set(PyMemoTable *self, PyObject *key, Py_ssize_t value)
  94. {
  95. PyMemoEntry *entry;
  96. + size_t desired_size;
  97. assert(key != NULL);
  98. @@ -831,10 +833,12 @@ PyMemoTable_Set(PyMemoTable *self, PyObject *key, Py_ssize_t value)
  99. * Very large memo tables (over 50K items) use doubling instead.
  100. * This may help applications with severe memory constraints.
  101. */
  102. - if (!(self->mt_used * 3 >= (self->mt_mask + 1) * 2))
  103. + if (SIZE_MAX / 3 >= self->mt_used && self->mt_used * 3 < self->mt_allocated * 2) {
  104. return 0;
  105. - return _PyMemoTable_ResizeTable(self,
  106. - (self->mt_used > 50000 ? 2 : 4) * self->mt_used);
  107. + }
  108. + // self->mt_used is always < PY_SSIZE_T_MAX, so this can't overflow.
  109. + desired_size = (self->mt_used > 50000 ? 2 : 4) * self->mt_used;
  110. + return _PyMemoTable_ResizeTable(self, desired_size);
  111. }
  112. #undef MT_MINSIZE
  113. @@ -1273,9 +1277,9 @@ _Unpickler_Readline(UnpicklerObject *self, char **result)
  114. /* Returns -1 (with an exception set) on failure, 0 on success. The memo array
  115. will be modified in place. */
  116. static int
  117. -_Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
  118. +_Unpickler_ResizeMemoList(UnpicklerObject *self, size_t new_size)
  119. {
  120. - Py_ssize_t i;
  121. + size_t i;
  122. assert(new_size > self->memo_size);
  123. @@ -1292,9 +1296,9 @@ _Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
  124. /* Returns NULL if idx is out of bounds. */
  125. static PyObject *
  126. -_Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
  127. +_Unpickler_MemoGet(UnpicklerObject *self, size_t idx)
  128. {
  129. - if (idx < 0 || idx >= self->memo_size)
  130. + if (idx >= self->memo_size)
  131. return NULL;
  132. return self->memo[idx];
  133. @@ -1303,7 +1307,7 @@ _Unpickler_MemoGet(UnpicklerObject *self, Py_ssize_t idx)
  134. /* Returns -1 (with an exception set) on failure, 0 on success.
  135. This takes its own reference to `value`. */
  136. static int
  137. -_Unpickler_MemoPut(UnpicklerObject *self, Py_ssize_t idx, PyObject *value)
  138. +_Unpickler_MemoPut(UnpicklerObject *self, size_t idx, PyObject *value)
  139. {
  140. PyObject *old_item;
  141. @@ -4194,14 +4198,13 @@ static PyObject *
  142. _pickle_PicklerMemoProxy_copy_impl(PicklerMemoProxyObject *self)
  143. /*[clinic end generated code: output=bb83a919d29225ef input=b73043485ac30b36]*/
  144. {
  145. - Py_ssize_t i;
  146. PyMemoTable *memo;
  147. PyObject *new_memo = PyDict_New();
  148. if (new_memo == NULL)
  149. return NULL;
  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. @@ -6620,7 +6623,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. @@ -6771,8 +6774,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. if (obj == NULL) {
  173. PyErr_SetString(PyExc_TypeError,
  174. @@ -6789,7 +6791,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
  175. if (new_memo == NULL)
  176. return -1;
  177. - for (i = 0; i < new_memo_size; i++) {
  178. + for (size_t i = 0; i < new_memo_size; i++) {
  179. Py_XINCREF(unpickler->memo[i]);
  180. new_memo[i] = unpickler->memo[i];
  181. }
  182. @@ -6837,8 +6839,7 @@ Unpickler_set_memo(UnpicklerObject *self, PyObject *obj)
  183. error:
  184. if (new_memo_size) {
  185. - i = new_memo_size;
  186. - while (--i >= 0) {
  187. + for (size_t i = new_memo_size - 1; i != SIZE_MAX; i--) {
  188. Py_XDECREF(new_memo[i]);
  189. }
  190. PyMem_FREE(new_memo);
  191. --
  192. 2.22.0.vfs.1.1.57.gbaf16c8