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
bytearray pop and remove Buffer Over-read #68655
Comments
The bytearray pop and remove methods suffer from buffer over-reads caused by memmove use under the assumption that PyByteArrayObject ob_size is less than ob_alloc, leading to a single byte over-read. This condition can be triggered by creating a bytearray from a range of length 0x10, then calling pop with a valid index: bytearray(range(0x10)).pop(0) The result is a memmove that reads off the end of src: 0:000> r If the over-read is allowed to succeed, a byte adjacent to the buffer is copied: 0:000> r However, a subsequent call to PyByteArray_Resize overwrites the copied byte with a null terminator: 0:000> p Because of this, these vulnerabilities should be classified as defense-in-depth. If PyByteArray_Resize could be forced to fail, or its behavior changes at a future date, it may become possible to exploit these issues to read adjacent memory. |
Offending code in 2.7: https://hg.python.org/cpython/file/20c9290a5de4/Objects/bytearrayobject.c#l2381 Let n = 16, where = 0; memmove() then attempts to copy (n - where) = 16 bytes where it should have copied 15, since we drop one. This appears to be a typical case of off-by-one. Changing (n - where) to (n - where - 1) should fix the issue. This underfows when (where + 1) > n, but this case is guarded against in bytearray_pop() and cannot occur in bytearray_remove(). The exact same memmove() invocation code is found in all 3.x branches as well. |
Attached is a patch that fixes the reported issue. Since there are no visible side effects in Python, I could not write a test for this. |
The bytearray object allocates one byte more for trailing null byte. ob_size always should be less than ob_alloc if ob_alloc != 0. But in rare cases when the bytearray is initialized with an iterator, this rule can be violated. Following patch restores this property. PyByteArray_AS_STRING() now always returns null-terminated string. |
If this is the case, then bpo-24462 should be fixed by this patch as well. I'm sorry about missing the root cause here. |
New changeset a887ce8611d2 by Serhiy Storchaka in branch '2.7': New changeset c95d7ffa492e by Serhiy Storchaka in branch '3.4': New changeset 942860bada14 by Serhiy Storchaka in branch '3.5': New changeset 97a24bc714ec by Serhiy Storchaka in branch 'default': |
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: