Patch: Win32 stack overflow

Christian Tismer tismer at appliedbiometrics.com
Wed Jun 2 06:13:05 EDT 1999


Patch for python15.dll

stack152.py

-- 
Christian Tismer             :^)   <mailto:tismer at appliedbiometrics.com>
Applied Biometrics GmbH      :     Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101   :    *Starship* http://starship.python.net
10553 Berlin                 :     PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint       E182 71C7 1A9D 66E9 9D15  D3CC D4D7 93E2 1FAE F6DF
     we're tired of banana software - shipped green, ripens at home
-------------- next part --------------
######################################
# patching Python 1.5.2 dll file
# to adjust maximum recusion depth.
# CT 990602

"""
What is this patch for?

Python 1.5.2 calls eval_code recursively for every
call of a python function. The current maximum
recursion depth is compiled into python15.dll
to be 10000.

My measures have shown that each recursive call
costs 104 bytes, when Python is compiled with MS VC++ 5.0.
The default stack size for a Windows program is 1 MB, and
this is slightly too few for 10000 calls.
The secure limit seems to be below 9610.

Note that this is no problem with MS VC++ 6.0, since
due to better register spilling, the stack growth per
recursion is only 100 byte :-)

Note also that for certain applications with different
stack requirements/compilation options, this patch might
be used to set the maximum recusion depth to any
arbitrary limit.

Test program:

def f():return f()

f()

After applying the patch, this sequence should give
a stack overflow error, but no general protection fault
any longer.

good luck - chris

"""

import string, struct, win32api

ORIG_OFFSET = 49785  # offset of signature in 1.5.2 orig dll
SIGNATURE = "\x89\x57\x0c\x3d"

DEF_FNAME = win32api.GetModuleFileName(win32api.GetModuleHandle("python15.dll"))

LIMIT = 9610 # secure under VC++ 5.0

def _get_stacksize(fname):
    """determine stack size of a Python 1.5.2 dll file"""
    f = open(fname, "rb")
    bin = f.read()
    if not string.find(bin, SIGNATURE) or len(string.split(bin, SIGNATURE)) != 2 :
        raise SystemError, "this is no python 1.5.2 dll file"
    else:
        offset = string.find(bin, SIGNATURE)
    off2 = offset+4
    word = bin[off2:off2+4]
    return offset, struct.unpack("i", word)[0]
    
def stacksize(fname):
    offset, stack = _get_stacksize(fname)
    if offset != ORIG_OFFSET:
        print "this is no standard Python 1.5.2 dll, but it seems to be valid"
    return stack
    
def patch(fnold, fnnew, size):
    bin = open(fnold, "rb").read()
    left, right = string.split(bin, SIGNATURE)
    right = struct.pack("i", size) + right[4:]
    bin = left + SIGNATURE + right
    open(fnnew, "wb").write(bin)

if __name__ == "__main__":
    ssize = stacksize(DEF_FNAME)
    print "Your current python recursion depth is %d" % ssize
    newsize = raw_input("stacksize = %d. Enter new size (to be sure, below %d)" \
       % (ssize, LIMIT))
    try:
        newsize = string.atoi(string.strip(newsize))
        old = DEF_FNAME
        new = old+".NEW"
        patch(old, new, newsize)
        print "File %s created with recusion depth of %d." % (new, newsize)
        print "please quit python, delete %s\n and rename %s to %s" % \
            (old, new, old)
    except ValueError:
        print "Recursion depth not changed."
        
# simply run this program.
# (c) Christian Tismer
# Professional Net Service GmbH


More information about the Python-list mailing list