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
Type confusion in json encoding #68871
Comments
on-35dm-i386-linux-gnu.so`encoder_listencode_list(s=0xb6f90394, acc=0xbfc42c28, seq=0xb6f2361c, indent_level=1) + 655 at _json.c:1800 frame #2: 0xb6e4366d _json.cpython-35dm-i386-linux-gnu.so`encoder_listencode_obj(s=0xb6f90394, acc=0xbfc42c28, obj=0xb6f2361c, indent_level=1) + 733 at _json.c:1554frame #3: 0xb6e3fc4f _json.cpython-35dm-i386-linux-gnu.so`encoder_call(self=0xb6f90394, args=0xb7049304, kwds=0x00000000) + 319 at _json.c:1386frame #4: 0x080c5758 python`PyObject_Call(func=0xb6f90394, arg=0xb7049304, kw=0x00000000) + 264 at abstract.c:2149This is a type confusion bug. encoder->markers can be initialized to anarbitrary object (string in this POC). PyDict_Contains trusts the caller that"op" is a dictionary without checking. Some callers can't be trusted :) |
I don't understand the issue. Can you elaborate? What is your code? What is the current result? What is the expected result? What is your platform? What is your Python version? etc. |
Sorry, I uploaded a test case. |
In encoder_init (the __init__ for _json.Encoder) s->marker is set to an argument of __init__, without any kind of type check, it can therefore be an arbitrary object. encoder_listencode_obj (and other functions) then use s->markers with the concrete API for dicts (such as PyDict_Contains). PyDict_Contains does not perform a type check, but casts its first argument to a PyDictObject and access fields. That causes problems when the marker isn't actually a dict. I don't know the module good enough to be 100% sure about a fix, but I think it would be best to add a type check to encoder_init. BTW. As far as I know _json.make_encoder is a private API and shouldn't be used directly, when you use the public API the argument will always be a dict. |
There is similar issue with key_separator and item_separator in 3.x. They are used with _PyAccu_Accumulate that performs a type check only in assert(). Here is a patch. |
Patch LGTM. |
New changeset b3d0bf112f70 by Serhiy Storchaka in branch '3.4': New changeset ef4d09399b99 by Serhiy Storchaka in branch '3.5': New changeset 7de4abf4eed2 by Serhiy Storchaka in branch 'default': |
New changeset 0a1266ef1b5d by Serhiy Storchaka in branch '2.7': |
Thank you for your report paul. Thanks for review Raymond. |
resolution: not a bug ^ because of private API? |
Since Serhiy pushed changes, the issue is fixed and it is a real bug. Thanks for the report paul. |
This was my fault. I want to set resolution to "fixed" but missed. Victor has corrected this. |
Proof of EIP control. |
GDB dump of running ./python eip.py
[007B:BFFFE20C]---------------------------------------------------------[stack] |
I can't reproduce your example paul. $ ./python eip.py
Traceback (most recent call last):
File "eip.py", line 21, in <module>
e = j.make_encoder(markers, None, enc, 4, "ks", "is", False, True, True)
TypeError: make_encoder() argument 1 must be dict or None, not array.array |
Can you try on 2.7 branch? |
The same result on 2.7 branch: $ ./python ../cpython/eip.py
Traceback (most recent call last):
File "../cpython/eip.py", line 21, in <module>
e = j.make_encoder(markers, None, enc, 4, "ks", "is", False, True, True)
TypeError: make_encoder() argument 1 must be dict or None, not str |
Sorry, I wasn't clear enough. This POC is a proof that the original bug can be used for EIP control. I just checked and it works as advertised on 2.7 revision: https://hg.python.org/cpython/rev/2d39777f3477 - it's a parent of https://hg.python.org/cpython/rev/0a1266ef1b5d containing the patch for this issue. I added this file, because I submitted a bug on hackerone claiming EIP control. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: