gh-156939: Fix xmlcharrefreplace() buffer overflow - #157109
Conversation
|
I wrote a patch for Python 3.14 to check if it's also affected: diff --git a/Include/internal/pycore_bytesobject.h b/Include/internal/pycore_bytesobject.h
index 8ea9b3ebb88..7ab96b109a5 100644
--- a/Include/internal/pycore_bytesobject.h
+++ b/Include/internal/pycore_bytesobject.h
@@ -86,6 +86,7 @@ typedef struct {
/* Stack buffer */
int use_small_buffer;
char small_buffer[512];
+ char canary_byte;
} _PyBytesWriter;
/* Initialize a bytes writer
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index 03245788bb1..be698236843 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -3456,6 +3456,7 @@ _PyBytesWriter_Init(_PyBytesWriter *writer)
memset(writer->small_buffer, PYMEM_CLEANBYTE,
sizeof(writer->small_buffer));
#endif
+ writer->canary_byte = 0xAB;
}
void
@@ -3524,6 +3525,8 @@ _PyBytesWriter_CheckConsistency(_PyBytesWriter *writer, char *str)
end = start + writer->allocated;
assert(str != NULL);
assert(start <= str && str <= end);
+
+ assert(writer->canary_byte == (char)0xAB);
return 1;
}
#endif
@@ -3665,6 +3668,10 @@ _PyBytesWriter_Finish(_PyBytesWriter *writer, void *str)
PyObject *result;
assert(_PyBytesWriter_CheckConsistency(writer, str));
+ if (writer->canary_byte != (char)0xAB) {
+ fprintf(stderr, "PyBytesWriter: buffer overflow detected! abort\n");
+ abort();
+ }
size = _PyBytesWriter_GetSize(writer, str);
if (size == 0 && !writer->use_bytearray) {I wrote a script to check for the buffer overflow in Python 3.14: Output: So yes, Python 3.14, which uses the old internal In Python 3.14, |
d1adc33 to
3bdaf2c
Compare
3bdaf2c to
aada0ed
Compare
Write into a temporay buffer to not write the trailing NUL byte.
aada0ed to
1c8742d
Compare
|
It seems like Python 3.10 to 3.16 are affected. (I didn't check older branches which no longer get security fixes.) |
|
@serhiy-storchaka: Would you mind to review this change? |
| Fix a buffer overflow in the ``xmlcharrefreplace`` error handler of 8-bit | ||
| encoding (such as ``ascii`` and ``latin1``). Previously, a buffer overflow | ||
| wrote one NUL byte in the stack memory if the output length was exactly 512 | ||
| bytes. Patch by Victor Stinner. |
There was a problem hiding this comment.
On Python 3.15 and 3.16, the new PyBytesWriter implementation is used. The NUL byte is written into PyBytesWriter.obj which is already a NULL pointer, so the write is harmless.
We should add the Changelog (NEWS) entry on Python 3.14 where the write occurs in the stack (buffer overflow).
Write into a temporay buffer to not write the trailing NUL byte.