diff options
author | David Malcolm <dmalcolm@redhat.com> | 2010-02-18 23:31:02 -0500 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2010-02-18 23:31:02 -0500 |
commit | e5826809d4b1bf545a41070caad23a013ce7817e (patch) | |
tree | 2f243b22726f9ec2d5a33139f8a2e560a01397e3 | |
parent | 36a517ef7848cbd0b3dcc7371f32e47ac4c87eba (diff) | |
download | libpython-e5826809d4b1bf545a41070caad23a013ce7817e.tar.gz libpython-e5826809d4b1bf545a41070caad23a013ce7817e.tar.xz libpython-e5826809d4b1bf545a41070caad23a013ce7817e.zip |
Introduce safety_limit and safe_range to protect against corrupt integer values; handle corrupt ob_type pointers
-rw-r--r-- | libpython.py | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/libpython.py b/libpython.py index afb9869..8af75f5 100644 --- a/libpython.py +++ b/libpython.py @@ -52,6 +52,17 @@ import gdb class NullPyObjectPtr(RuntimeError): pass +def safety_limit(val): + # Given a integer value from the process being debugged, limit it to some + # safety threshold so that arbitrary breakage within said process doesn't + # break the gdb process too much (e.g. sizes of iterations, sizes of lists) + return min(val, 100) + +def safe_range(val): + # As per range, but don't trust the value too much: cap it to a safety + # threshold in case the data was corrupted + return xrange(safety_limit(val)) + def is_py3k(): # This code assumes that a libpython's DWARF data has actually been # loaded by the point that this function is called @@ -150,6 +161,9 @@ class PyObjectPtr(object): except NullPyObjectPtr: # NULL tp_name? tp_name = 'unknown' + except RuntimeError: + # Can't even read the object at all? + tp_name = 'unknown' return FakeRepr(tp_name, long(self._gdbval)) @@ -238,7 +252,7 @@ class PyDictObjectPtr(PyObjectPtr): def proxyval(self): result = {} - for i in xrange(self.field('ma_mask')): + for i in safe_range(self.field('ma_mask')): ep = self.field('ma_table') + i pvalue = PyObjectPtr.from_pyobject_ptr(ep['me_value']) if not pvalue.is_null(): @@ -285,7 +299,7 @@ class PyListObjectPtr(PyObjectPtr): def proxyval(self): result = [PyObjectPtr.from_pyobject_ptr(self[i]).proxyval() - for i in range(int_from_int(self.field('ob_size')))] + for i in safe_range(int_from_int(self.field('ob_size')))] return result class PyLongObjectPtr(PyObjectPtr): @@ -321,7 +335,7 @@ class PyLongObjectPtr(PyObjectPtr): # FIXME: I haven't yet tested this case SHIFT = 30L - digits = [long(ob_digit[i]) * 2**(SHIFT*i) for i in xrange(abs(ob_size))] + digits = [long(ob_digit[i]) * 2**(SHIFT*i) for i in safe_range(abs(ob_size))] result = sum(digits) if ob_size < 0: result = -result @@ -357,7 +371,7 @@ class PyTupleObjectPtr(PyObjectPtr): def proxyval(self): result = tuple([PyObjectPtr.from_pyobject_ptr(self[i]).proxyval() - for i in range(int_from_int(self.field('ob_size')))]) + for i in safe_range(int_from_int(self.field('ob_size')))]) return result class PyTypeObjectPtr(PyObjectPtr): @@ -375,7 +389,7 @@ class PyUnicodeObjectPtr(PyObjectPtr): # Gather a list of ints from the Py_UNICODE array; these are either # UCS-2 or UCS-4 code points: - Py_UNICODEs = [int(field_str[i]) for i in xrange(field_length)] + Py_UNICODEs = [int(field_str[i]) for i in safe_range(field_length)] # Convert the int code points to unicode characters, and generate a # local unicode instance: @@ -409,7 +423,7 @@ class FrameInfo: self.co_varnames = PyTupleObjectPtr.from_pyobject_ptr(self.co.field('co_varnames')) self.locals = [] # list of kv pairs f_localsplus = self.fval.field('f_localsplus') - for i in xrange(min(self.co_nlocals, 200)): # arbitrary upper sanity limit in case co_nlocals is corrupt + for i in safe_range(self.co_nlocals): #print 'i=%i' % i value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i]) if not value.is_null(): |