1 |
From 448138f1a976bd6311a5eefb34e5e9e6f102b83a Mon Sep 17 00:00:00 2001 |
2 |
From: Anssi Hannula <anssi.hannula@iki.fi> |
3 |
Date: Sat, 13 Nov 2010 08:25:46 +0200 |
4 |
Subject: [PATCH 07/15] fixed: CVE-2008-3142 in internal python (Gentoo) |
5 |
|
6 |
--- |
7 |
xbmc/lib/libPython/Python/Include/pymem.h | 33 ++++++++++++++------- |
8 |
xbmc/lib/libPython/Python/Misc/NEWS | 7 ++++ |
9 |
xbmc/lib/libPython/Python/Modules/almodule.c | 2 + |
10 |
xbmc/lib/libPython/Python/Modules/arraymodule.c | 8 +++-- |
11 |
xbmc/lib/libPython/Python/Modules/selectmodule.c | 4 ++- |
12 |
xbmc/lib/libPython/Python/Objects/obmalloc.c | 18 ++++++++++++ |
13 |
6 files changed, 57 insertions(+), 15 deletions(-) |
14 |
|
15 |
diff --git a/xbmc/lib/libPython/Python/Include/pymem.h b/xbmc/lib/libPython/Python/Include/pymem.h |
16 |
index 0e18f03..a3eb095 100644 |
17 |
--- a/xbmc/lib/libPython/Python/Include/pymem.h |
18 |
+++ b/xbmc/lib/libPython/Python/Include/pymem.h |
19 |
@@ -66,8 +66,12 @@ PyAPI_FUNC(void) PyMem_Free(void *); |
20 |
for malloc(0), which would be treated as an error. Some platforms |
21 |
would return a pointer with no memory behind it, which would break |
22 |
pymalloc. To solve these problems, allocate an extra byte. */ |
23 |
-#define PyMem_MALLOC(n) malloc((n) ? (n) : 1) |
24 |
-#define PyMem_REALLOC(p, n) realloc((p), (n) ? (n) : 1) |
25 |
+/* Returns NULL to indicate error if a negative size or size larger than |
26 |
+ Py_ssize_t can represent is supplied. Helps prevents security holes. */ |
27 |
+#define PyMem_MALLOC(n) (((n) < 0 || (n) > INT_MAX) ? NULL \ |
28 |
+ : malloc((n) ? (n) : 1)) |
29 |
+#define PyMem_REALLOC(p, n) (((n) < 0 || (n) > INT_MAX) ? NULL \ |
30 |
+ : realloc((p), (n) ? (n) : 1)) |
31 |
|
32 |
#endif /* PYMALLOC_DEBUG */ |
33 |
|
34 |
@@ -80,24 +84,31 @@ PyAPI_FUNC(void) PyMem_Free(void *); |
35 |
* Type-oriented memory interface |
36 |
* ============================== |
37 |
* |
38 |
- * These are carried along for historical reasons. There's rarely a good |
39 |
- * reason to use them anymore (you can just as easily do the multiply and |
40 |
- * cast yourself). |
41 |
+ * Allocate memory for n objects of the given type. Returns a new pointer |
42 |
+ * or NULL if the request was too large or memory allocation failed. Use |
43 |
+ * these macros rather than doing the multiplication yourself so that proper |
44 |
+ * overflow checking is always done. |
45 |
*/ |
46 |
|
47 |
#define PyMem_New(type, n) \ |
48 |
- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ |
49 |
+ ( ((n) > INT_MAX / sizeof(type)) ? NULL : \ |
50 |
( (type *) PyMem_Malloc((n) * sizeof(type)) ) ) |
51 |
#define PyMem_NEW(type, n) \ |
52 |
- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ |
53 |
+ ( ((n) > INT_MAX / sizeof(type)) ? NULL : \ |
54 |
( (type *) PyMem_MALLOC((n) * sizeof(type)) ) ) |
55 |
|
56 |
+/* |
57 |
+ * The value of (p) is always clobbered by this macro regardless of success. |
58 |
+ * The caller MUST check if (p) is NULL afterwards and deal with the memory |
59 |
+ * error if so. This means the original value of (p) MUST be saved for the |
60 |
+ * caller's memory error handler to not lose track of it. |
61 |
+ */ |
62 |
#define PyMem_Resize(p, type, n) \ |
63 |
- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ |
64 |
- ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) ) |
65 |
+ ( (p) = ((n) > INT_MAX / sizeof(type)) ? NULL : \ |
66 |
+ (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) |
67 |
#define PyMem_RESIZE(p, type, n) \ |
68 |
- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ |
69 |
- ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) ) |
70 |
+ ( (p) = ((n) > INT_MAX / sizeof(type)) ? NULL : \ |
71 |
+ (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) |
72 |
|
73 |
/* In order to avoid breaking old code mixing PyObject_{New, NEW} with |
74 |
PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory" |
75 |
diff --git a/xbmc/lib/libPython/Python/Misc/NEWS b/xbmc/lib/libPython/Python/Misc/NEWS |
76 |
index 1c33e2c..39fa7be 100644 |
77 |
--- a/xbmc/lib/libPython/Python/Misc/NEWS |
78 |
+++ b/xbmc/lib/libPython/Python/Misc/NEWS |
79 |
@@ -18,6 +18,13 @@ What's New in Python 2.4.5c1? |
80 |
Core and builtins |
81 |
----------------- |
82 |
|
83 |
+- Issue #2620: Overflow checking when allocating or reallocating memory |
84 |
+ was not always being done properly in some python types and extension |
85 |
+ modules. PyMem_MALLOC, PyMem_REALLOC, PyMem_NEW and PyMem_RESIZE have |
86 |
+ all been updated to perform better checks and places in the code that |
87 |
+ would previously leak memory on the error path when such an allocation |
88 |
+ failed have been fixed. |
89 |
+ |
90 |
- Added checks for integer overflows, contributed by Google. Some are |
91 |
only available if asserts are left in the code, in cases where they |
92 |
can't be triggered from Python code. |
93 |
diff --git a/xbmc/lib/libPython/Python/Modules/almodule.c b/xbmc/lib/libPython/Python/Modules/almodule.c |
94 |
index fbeb13a..20f26d0 100644 |
95 |
--- a/xbmc/lib/libPython/Python/Modules/almodule.c |
96 |
+++ b/xbmc/lib/libPython/Python/Modules/almodule.c |
97 |
@@ -1633,9 +1633,11 @@ al_QueryValues(PyObject *self, PyObject *args) |
98 |
if (nvals < 0) |
99 |
goto cleanup; |
100 |
if (nvals > setsize) { |
101 |
+ ALvalue *old_return_set = return_set; |
102 |
setsize = nvals; |
103 |
PyMem_RESIZE(return_set, ALvalue, setsize); |
104 |
if (return_set == NULL) { |
105 |
+ return_set = old_return_set; |
106 |
PyErr_NoMemory(); |
107 |
goto cleanup; |
108 |
} |
109 |
diff --git a/xbmc/lib/libPython/Python/Modules/arraymodule.c b/xbmc/lib/libPython/Python/Modules/arraymodule.c |
110 |
index aea4773..f7ad5be 100644 |
111 |
--- a/xbmc/lib/libPython/Python/Modules/arraymodule.c |
112 |
+++ b/xbmc/lib/libPython/Python/Modules/arraymodule.c |
113 |
@@ -814,6 +814,7 @@ static int |
114 |
array_do_extend(arrayobject *self, PyObject *bb) |
115 |
{ |
116 |
int size; |
117 |
+ char *old_item; |
118 |
|
119 |
if (!array_Check(bb)) |
120 |
return array_iter_extend(self, bb); |
121 |
@@ -829,10 +830,11 @@ array_do_extend(arrayobject *self, PyObject *bb) |
122 |
return -1; |
123 |
} |
124 |
size = self->ob_size + b->ob_size; |
125 |
+ old_item = self->ob_item; |
126 |
PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize); |
127 |
if (self->ob_item == NULL) { |
128 |
- PyObject_Del(self); |
129 |
- PyErr_NoMemory(); |
130 |
+ self->ob_item = old_item; |
131 |
+ PyErr_NoMemory(); |
132 |
return -1; |
133 |
} |
134 |
memcpy(self->ob_item + self->ob_size*self->ob_descr->itemsize, |
135 |
@@ -884,7 +886,7 @@ array_inplace_repeat(arrayobject *self, int n) |
136 |
if (size > INT_MAX / n) { |
137 |
return PyErr_NoMemory(); |
138 |
} |
139 |
- PyMem_Resize(items, char, n * size); |
140 |
+ PyMem_RESIZE(items, char, n * size); |
141 |
if (items == NULL) |
142 |
return PyErr_NoMemory(); |
143 |
p = items; |
144 |
diff --git a/xbmc/lib/libPython/Python/Modules/selectmodule.c b/xbmc/lib/libPython/Python/Modules/selectmodule.c |
145 |
index 53c68c1..25e2310 100644 |
146 |
--- a/xbmc/lib/libPython/Python/Modules/selectmodule.c |
147 |
+++ b/xbmc/lib/libPython/Python/Modules/selectmodule.c |
148 |
@@ -342,10 +342,12 @@ update_ufd_array(pollObject *self) |
149 |
{ |
150 |
int i, pos; |
151 |
PyObject *key, *value; |
152 |
+ struct pollfd *old_ufds = self->ufds; |
153 |
|
154 |
self->ufd_len = PyDict_Size(self->dict); |
155 |
- PyMem_Resize(self->ufds, struct pollfd, self->ufd_len); |
156 |
+ PyMem_RESIZE(self->ufds, struct pollfd, self->ufd_len); |
157 |
if (self->ufds == NULL) { |
158 |
+ self->ufds = old_ufds; |
159 |
PyErr_NoMemory(); |
160 |
return 0; |
161 |
} |
162 |
diff --git a/xbmc/lib/libPython/Python/Objects/obmalloc.c b/xbmc/lib/libPython/Python/Objects/obmalloc.c |
163 |
index a6fdf40..163c126 100644 |
164 |
--- a/xbmc/lib/libPython/Python/Objects/obmalloc.c |
165 |
+++ b/xbmc/lib/libPython/Python/Objects/obmalloc.c |
166 |
@@ -585,6 +585,15 @@ PyObject_Malloc(size_t nbytes) |
167 |
uint size; |
168 |
|
169 |
/* |
170 |
+ * Limit ourselves to INT_MAX bytes to prevent security holes. |
171 |
+ * Most python internals blindly use a signed Py_ssize_t to track |
172 |
+ * things without checking for overflows or negatives. |
173 |
+ * As size_t is unsigned, checking for nbytes < 0 is not required. |
174 |
+ */ |
175 |
+ if (nbytes > INT_MAX) |
176 |
+ return NULL; |
177 |
+ |
178 |
+ /* |
179 |
* This implicitly redirects malloc(0). |
180 |
*/ |
181 |
if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { |
182 |
@@ -814,6 +823,15 @@ PyObject_Realloc(void *p, size_t nbytes) |
183 |
if (p == NULL) |
184 |
return PyObject_Malloc(nbytes); |
185 |
|
186 |
+ /* |
187 |
+ * Limit ourselves to INT_MAX bytes to prevent security holes. |
188 |
+ * Most python internals blindly use a signed Py_ssize_t to track |
189 |
+ * things without checking for overflows or negatives. |
190 |
+ * As size_t is unsigned, checking for nbytes < 0 is not required. |
191 |
+ */ |
192 |
+ if (nbytes > INT_MAX) |
193 |
+ return NULL; |
194 |
+ |
195 |
pool = POOL_ADDR(p); |
196 |
if (Py_ADDRESS_IN_RANGE(p, pool)) { |
197 |
/* We're in charge of this block */ |
198 |
-- |
199 |
1.7.3 |
200 |
|