Issue #24456: Fixed possible buffer over-read in adpcm2lin() and lin2adpcm()
functions of the audioop module. Fixed SystemError when the state is not a
tuple. Fixed possible memory leak.
diff --git a/Lib/test/test_audioop.py b/Lib/test/test_audioop.py
index ceaf2a3..4af7350 100644
--- a/Lib/test/test_audioop.py
+++ b/Lib/test/test_audioop.py
@@ -210,6 +210,21 @@
self.assertEqual(audioop.lin2adpcm(b'\0' * w * 10, w, None),
(b'\0' * 5, (0, 0)))
+ def test_invalid_adpcm_state(self):
+ # state must be a tuple or None, not an integer
+ self.assertRaises(TypeError, audioop.adpcm2lin, b'\0', 1, 555)
+ self.assertRaises(TypeError, audioop.lin2adpcm, b'\0', 1, 555)
+ # Issues #24456, #24457: index out of range
+ self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0, -1))
+ self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0, 89))
+ self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0, -1))
+ self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0, 89))
+ # value out of range
+ self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (-0x8001, 0))
+ self.assertRaises(ValueError, audioop.adpcm2lin, b'\0', 1, (0x8000, 0))
+ self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (-0x8001, 0))
+ self.assertRaises(ValueError, audioop.lin2adpcm, b'\0', 1, (0x8000, 0))
+
def test_lin2alaw(self):
self.assertEqual(audioop.lin2alaw(datas[1], 1),
b'\xd5\x87\xa4\x24\xaa\x2a\x5a')
diff --git a/Misc/NEWS b/Misc/NEWS
index 1496398..9418ad2 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -30,6 +30,10 @@
Library
-------
+- Issue #24456: Fixed possible buffer over-read in adpcm2lin() and lin2adpcm()
+ functions of the audioop module. Fixed SystemError when the state is not a
+ tuple. Fixed possible memory leak.
+
- Issue #24481: Fix possible memory corruption with large profiler info strings
in hotshot.
diff --git a/Modules/audioop.c b/Modules/audioop.c
index 0282c7e..4d3b679 100644
--- a/Modules/audioop.c
+++ b/Modules/audioop.c
@@ -1420,18 +1420,29 @@
if (!audioop_check_parameters(len, size))
return NULL;
- str = PyString_FromStringAndSize(NULL, len/(size*2));
- if ( str == 0 )
- return 0;
- ncp = (signed char *)PyString_AsString(str);
-
/* Decode state, should have (value, step) */
if ( state == Py_None ) {
/* First time, it seems. Set defaults */
valpred = 0;
index = 0;
- } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) )
+ }
+ else if (!PyTuple_Check(state)) {
+ PyErr_SetString(PyExc_TypeError, "state must be a tuple or None");
+ return NULL;
+ }
+ else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) {
+ return NULL;
+ }
+ else if (valpred >= 0x8000 || valpred < -0x8000 ||
+ (size_t)index >= sizeof(stepsizeTable)/sizeof(stepsizeTable[0])) {
+ PyErr_SetString(PyExc_ValueError, "bad state");
+ return NULL;
+ }
+
+ str = PyString_FromStringAndSize(NULL, len/(size*2));
+ if ( str == 0 )
return 0;
+ ncp = (signed char *)PyString_AsString(str);
step = stepsizeTable[index];
bufferstep = 1;
@@ -1529,8 +1540,19 @@
/* First time, it seems. Set defaults */
valpred = 0;
index = 0;
- } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) )
- return 0;
+ }
+ else if (!PyTuple_Check(state)) {
+ PyErr_SetString(PyExc_TypeError, "state must be a tuple or None");
+ return NULL;
+ }
+ else if (!PyArg_ParseTuple(state, "ii", &valpred, &index)) {
+ return NULL;
+ }
+ else if (valpred >= 0x8000 || valpred < -0x8000 ||
+ (size_t)index >= sizeof(stepsizeTable)/sizeof(stepsizeTable[0])) {
+ PyErr_SetString(PyExc_ValueError, "bad state");
+ return NULL;
+ }
if (len > (INT_MAX/2)/size) {
PyErr_SetString(PyExc_MemoryError,