mirror of
https://github.com/python/cpython.git
synced 2025-12-31 04:23:37 +00:00
[3.13] gh-142783: Fix possible use after free in zoneinfo module (GH-142790) (GH-142861)
(cherry picked from commit 8307a14d0e)
Co-authored-by: wangxiaolei <fatelei@gmail.com>
This commit is contained in:
parent
9361207bc2
commit
88b8e63c54
3 changed files with 30 additions and 7 deletions
|
|
@ -1551,6 +1551,26 @@ def __eq__(self, other):
|
|||
except CustomError:
|
||||
pass
|
||||
|
||||
def test_weak_cache_descriptor_use_after_free(self):
|
||||
class BombDescriptor:
|
||||
def __get__(self, obj, owner):
|
||||
return {}
|
||||
|
||||
class EvilZoneInfo(self.klass):
|
||||
pass
|
||||
|
||||
# Must be set after the class creation.
|
||||
EvilZoneInfo._weak_cache = BombDescriptor()
|
||||
|
||||
key = "America/Los_Angeles"
|
||||
zone1 = EvilZoneInfo(key)
|
||||
self.assertEqual(str(zone1), key)
|
||||
|
||||
EvilZoneInfo.clear_cache()
|
||||
zone2 = EvilZoneInfo(key)
|
||||
self.assertEqual(str(zone2), key)
|
||||
self.assertIsNot(zone2, zone1)
|
||||
|
||||
|
||||
class CZoneInfoCacheTest(ZoneInfoCacheTest):
|
||||
module = c_zoneinfo
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Fix zoneinfo use-after-free with descriptor _weak_cache. a descriptor as _weak_cache could cause crashes during object creation. The fix ensures proper reference counting for descriptor-provided objects.
|
||||
|
|
@ -287,16 +287,11 @@ static PyObject *
|
|||
get_weak_cache(zoneinfo_state *state, PyTypeObject *type)
|
||||
{
|
||||
if (type == state->ZoneInfoType) {
|
||||
Py_INCREF(state->ZONEINFO_WEAK_CACHE);
|
||||
return state->ZONEINFO_WEAK_CACHE;
|
||||
}
|
||||
else {
|
||||
PyObject *cache =
|
||||
PyObject_GetAttrString((PyObject *)type, "_weak_cache");
|
||||
// We are assuming that the type lives at least as long as the function
|
||||
// that calls get_weak_cache, and that it holds a reference to the
|
||||
// cache, so we'll return a "borrowed reference".
|
||||
Py_XDECREF(cache);
|
||||
return cache;
|
||||
return PyObject_GetAttrString((PyObject *)type, "_weak_cache");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,6 +318,7 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
|
|||
PyObject *weak_cache = get_weak_cache(state, type);
|
||||
instance = PyObject_CallMethod(weak_cache, "get", "O", key, Py_None);
|
||||
if (instance == NULL) {
|
||||
Py_DECREF(weak_cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +326,7 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
|
|||
Py_DECREF(instance);
|
||||
PyObject *tmp = zoneinfo_new_instance(state, type, key);
|
||||
if (tmp == NULL) {
|
||||
Py_DECREF(weak_cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -337,12 +334,14 @@ zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
|
|||
PyObject_CallMethod(weak_cache, "setdefault", "OO", key, tmp);
|
||||
Py_DECREF(tmp);
|
||||
if (instance == NULL) {
|
||||
Py_DECREF(weak_cache);
|
||||
return NULL;
|
||||
}
|
||||
((PyZoneInfo_ZoneInfo *)instance)->source = SOURCE_CACHE;
|
||||
}
|
||||
|
||||
update_strong_cache(state, type, key, instance);
|
||||
Py_DECREF(weak_cache);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
@ -504,12 +503,14 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls,
|
|||
PyObject *item = NULL;
|
||||
PyObject *pop = PyUnicode_FromString("pop");
|
||||
if (pop == NULL) {
|
||||
Py_DECREF(weak_cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *iter = PyObject_GetIter(only_keys);
|
||||
if (iter == NULL) {
|
||||
Py_DECREF(pop);
|
||||
Py_DECREF(weak_cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -534,6 +535,7 @@ zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls,
|
|||
Py_DECREF(pop);
|
||||
}
|
||||
|
||||
Py_DECREF(weak_cache);
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue