From ddc63ebe9b52c0ab4ba033301e70fac89f610704 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 10 Jan 2010 21:10:01 +0100 Subject: [PATCH] audioop: check that length is a multiple the size Most functions of audioop takes as input a byte string (audio data) and a size argument (number of bytes of a sample). Functions don't check that the byte string length is a multiple of the size. It leads to read and write from/to uninitialised memory and might crash. Example on writing into uninitilized memory: $ python -c "import audioop; audioop.reverse('X', 2)" Fatal Python error: Inconsistent interned string state. Abandon It allocates a string of 1 byte and write 2 bytes into this string => memory corruption. Attached patch creates audioop_check_size() and audioop_check_parameters() functions. --- Modules/audioop.c | 153 ++++++++++++++++++++++++---------------------------- 1 files changed, 71 insertions(+), 82 deletions(-) diff --git a/Modules/audioop.c b/Modules/audioop.c index 42daf9b..ebb992a 100644 --- a/Modules/audioop.c +++ b/Modules/audioop.c @@ -295,6 +295,29 @@ static int stepsizeTable[89] = { static PyObject *AudioopError; +static int +audioop_check_size(int size) +{ + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } else { + return 1; + } +} + +static int +audioop_check_parameters(int len, int size) +{ + if (!audioop_check_size(size)) + return 0; + if ( len % size != 0 ) { + PyErr_SetString(AudioopError, "not a whole number of frames"); + return 0; + } + return 1; +} + static PyObject * audioop_getsample(PyObject *self, PyObject *args) { @@ -304,10 +327,8 @@ audioop_getsample(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#ii:getsample", &cp, &len, &size, &i) ) return 0; - if ( size != 1 && size != 2 && size != 4 ) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_parameters(len, size)) + return NULL; if ( i < 0 || i >= len/size ) { PyErr_SetString(AudioopError, "Index out of range"); return 0; @@ -328,10 +349,8 @@ audioop_max(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) ) return 0; - if ( size != 1 && size != 2 && size != 4 ) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_parameters(len, size)) + return NULL; for ( i=0; i 0,1 */ for ( i=0; i= 1"); return NULL; @@ -1269,11 +1277,8 @@ audioop_lin2ulaw(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#i:lin2ulaw", &cp, &len, &size) ) return 0 ; - - if ( size != 1 && size != 2 && size != 4) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_parameters(len, size)) + return NULL; rv = PyString_FromStringAndSize(NULL, len/size); if ( rv == 0 ) @@ -1303,11 +1308,8 @@ audioop_ulaw2lin(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#i:ulaw2lin", &cp, &len, &size) ) return 0; - - if ( size != 1 && size != 2 && size != 4) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_size(size)) + return NULL; new_len = len*size; if (new_len < 0) { @@ -1343,11 +1345,8 @@ audioop_lin2alaw(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#i:lin2alaw", &cp, &len, &size) ) return 0; - - if ( size != 1 && size != 2 && size != 4) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_parameters(len, size)) + return NULL; rv = PyString_FromStringAndSize(NULL, len/size); if ( rv == 0 ) @@ -1377,11 +1376,8 @@ audioop_alaw2lin(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#i:alaw2lin", &cp, &len, &size) ) return 0; - - if ( size != 1 && size != 2 && size != 4) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_size(size)) + return NULL; new_len = len*size; if (new_len < 0) { @@ -1418,12 +1414,8 @@ audioop_lin2adpcm(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#iO:lin2adpcm", &cp, &len, &size, &state) ) return 0; - - - if ( size != 1 && size != 2 && size != 4) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_parameters(len, size)) + return NULL; str = PyString_FromStringAndSize(NULL, len/(size*2)); if ( str == 0 ) @@ -1526,11 +1518,8 @@ audioop_adpcm2lin(PyObject *self, PyObject *args) if ( !PyArg_ParseTuple(args, "s#iO:adpcm2lin", &cp, &len, &size, &state) ) return 0; - - if ( size != 1 && size != 2 && size != 4) { - PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); - return 0; - } + if (!audioop_check_size(size)) + return NULL; /* Decode state, should have (value, step) */ if ( state == Py_None ) { -- 1.6.0.4