Skip to content

Commit 1d41002

Browse files
committed
gh-XXXXX: Add ndim validation to PyBuffer_ToContiguous for defense-in-depth
Add validation of the ndim parameter in PyBuffer_ToContiguous() and buffer_to_contiguous() to prevent potential integer overflow in memory allocation calculations. While Python-level code already enforces PyBUF_MAX_NDIM (64), C extensions implementing custom getbufferproc could potentially provide invalid ndim values. This change adds defense-in-depth validation to ensure ndim is within the valid range before performing allocations. The allocation calculation \3 * src->ndim * sizeof(Py_ssize_t)\ could theoretically overflow if ndim exceeds ~3.8e17 on 64-bit systems, though this is not practically exploitable. This patch adds explicit validation as a hardening measure. Changes: - PyBuffer_ToContiguous(): Add runtime check for ndim range - buffer_to_contiguous(): Add assertion for ndim <= PyBUF_MAX_NDIM - Add test case in test_memoryview.py This is a hardening improvement, not a fix for an actively exploitable vulnerability. Co-authored-by: Lakshmikanthan K <badassletchu@gmail.com>
1 parent 5466f57 commit 1d41002

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

Lib/test/test_memoryview.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,20 @@ def test_picklebuffer_reference_loop(self):
861861
gc.collect()
862862
self.assertIsNone(wr())
863863

864+
def test_ndim_limit(self):
865+
# gh-XXXXX: Ensure ndim is validated to prevent integer overflow
866+
# PyBUF_MAX_NDIM is 64
867+
b = bytearray(b"A" * 100)
868+
m = memoryview(b)
869+
870+
# Test that exceeding PyBUF_MAX_NDIM raises ValueError
871+
with self.assertRaisesRegex(ValueError, "must not exceed 64"):
872+
m.cast('B', shape=tuple([1] * 65))
873+
874+
# Test that negative ndim is rejected
875+
with self.assertRaises((ValueError, TypeError)):
876+
m.cast('B', shape=tuple([-1]))
877+
864878

865879
@threading_helper.requires_working_threading()
866880
@support.requires_resource("cpu")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Add validation of the ``ndim`` parameter in :c:func:`PyBuffer_ToContiguous`
2+
to prevent potential integer overflow in memory allocation calculations.
3+
While Python-level code already enforces :c:macro:`PyBUF_MAX_NDIM`, this
4+
change adds defense-in-depth validation for C extensions that might provide
5+
invalid values. Patch by Lakshmikanthan K.

Objects/memoryobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ buffer_to_contiguous(char *mem, const Py_buffer *src, char order)
500500
int ret;
501501

502502
assert(src->ndim >= 1);
503+
assert(src->ndim <= PyBUF_MAX_NDIM);
503504
assert(src->shape != NULL);
504505
assert(src->strides != NULL);
505506

@@ -1059,6 +1060,16 @@ PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char orde
10591060
return -1;
10601061
}
10611062

1063+
/* Validate ndim to prevent potential integer overflow in allocation.
1064+
* While Python-level code enforces PyBUF_MAX_NDIM, C extensions could
1065+
* potentially provide invalid values. This is a defense-in-depth check. */
1066+
if (src->ndim < 0 || src->ndim > PyBUF_MAX_NDIM) {
1067+
PyErr_Format(PyExc_ValueError,
1068+
"ndim out of valid range (got %d, expected 0-%d)",
1069+
src->ndim, PyBUF_MAX_NDIM);
1070+
return -1;
1071+
}
1072+
10621073
if (PyBuffer_IsContiguous(src, order)) {
10631074
memcpy((char *)buf, src->buf, len);
10641075
return 0;
@@ -1086,6 +1097,7 @@ PyBuffer_ToContiguous(void *buf, const Py_buffer *src, Py_ssize_t len, char orde
10861097
return ret;
10871098
}
10881099

1100+
10891101
static inline Py_ssize_t
10901102
get_exports(PyMemoryViewObject *buf)
10911103
{

0 commit comments

Comments
 (0)