-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-126119: fix some crashes in code objects if co_stacksize
is absurdly large
#126122
base: main
Are you sure you want to change the base?
Conversation
I found out that this won't be sufficient so converting it to a draft for now until I patch more attackable entrypoints. |
How about rejecting excessively large |
That's what I'm actually doing (or am I not?) [It's just that the expression to check is not the best one and I'm trying to see if I can make other place of the code overflow with: if ((size_t)con->stacksize
>= (INT_MAX / sizeof(PyObject *)) - FRAME_SPECIALS_SIZE - nlocalsplus)
{
PyErr_SetString(PyExc_OverflowError, "code: co_stacksize is too large");
return -1;
} |
Ok, I found different issues. It's possible to bypass the check in the code object validator that I added when attacking generator's frames. I'll need a bit more time for that but I won't be coding anymore today. The evil size that should be checked in code constructor is "((_testcapi.INT_MAX - 10) // sizeof(PyObject *))" but the following crashes: ps = ctypes.sizeof(ctypes.c_void_p) # sizeof(PyObject *)
smallest_evil_co_stacksize = (_testcapi.INT_MAX // ps) - 10
evil = f().gi_frame.f_code.__replace__(co_stacksize=smallest_evil_co_stacksize - 1) # ok
evil_gi = types.FunctionType(evil, {})() # crashes
self.assertRaises(OverflowError, evil_gi.__sizeof__) # crashes With |
I meant choose a large value, rather than checking for overflow. Something like |
Do you have a good value in mind? I'm not sure if it could affect recursion limit for instance or tracebacks if you change the stacksize (clearly not an expert here). I'm going offline now but we can continue this discussion tomorrow. Also, maybe I could find a way to pass the check in the code object but make it crash when creating fake generators. So the choice of EDIT (30th October): I'm not sure I'll be able to work on that today (I have some IRL stuff to do and won't be available today a lot). |
The free-threaded build crashes (just with "Segmentation fault (core dumped)", no traceback) but I don't know why... @colesbury do you have some idea? The bad code is import types
def f(): yield
code = f().gi_frame.f_code
evil_code = code.__replace__(co_stacksize=268435444) # OK
evil_gi_func = types.FunctionType(evil_code, {}) # OK
evil_gi = evil_gi_func() # not ok! |
co_framesize
if co_stacksize
is absurdely largeco_stacksize
is absurdely large
I'll take a look at the feee-threaded failures. |
That's what I'm actually doing. It's exactly the check I'm performing but I wonder why (Thanks for finding it btw) |
For the evil example above, I have |
co_stacksize
is absurdely largeco_stacksize
is absurdly large
Misc/NEWS.d/next/Core_and_Builtins/2024-10-29-11-47-19.gh-issue-126119.xbAvxt.rst
Outdated
Show resolved
Hide resolved
…e-126119.xbAvxt.rst
__sizeof__
of objects with underlying code objects #126119