Merged revisions 82492 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r82492 | victor.stinner | 2010-07-03 15:36:19 +0200 (sam., 03 juil. 2010) | 3 lines

  Issue #7673: Fix security vulnerability (CVE-2010-2089) in the audioop module,
  ensure that the input string length is a multiple of the frame size
........
This commit is contained in:
Victor Stinner 2010-07-03 13:44:22 +00:00
parent 4833e5b874
commit bc5c54bca2
3 changed files with 108 additions and 74 deletions

View File

@ -20,6 +20,12 @@ def gendata4():
data = [gendata1(), gendata2(), gendata4()] data = [gendata1(), gendata2(), gendata4()]
INVALID_DATA = [
('abc', 0),
('abc', 2),
('abc', 4),
]
class TestAudioop(unittest.TestCase): class TestAudioop(unittest.TestCase):
@ -168,6 +174,33 @@ class TestAudioop(unittest.TestCase):
self.assertRaises(audioop.error, self.assertRaises(audioop.error,
audioop.findmax, ''.join(chr(x) for x in range(256)), -2392392) audioop.findmax, ''.join(chr(x) for x in range(256)), -2392392)
def test_issue7673(self):
state = None
for data, size in INVALID_DATA:
size2 = size
self.assertRaises(audioop.error, audioop.getsample, data, size, 0)
self.assertRaises(audioop.error, audioop.max, data, size)
self.assertRaises(audioop.error, audioop.minmax, data, size)
self.assertRaises(audioop.error, audioop.avg, data, size)
self.assertRaises(audioop.error, audioop.rms, data, size)
self.assertRaises(audioop.error, audioop.avgpp, data, size)
self.assertRaises(audioop.error, audioop.maxpp, data, size)
self.assertRaises(audioop.error, audioop.cross, data, size)
self.assertRaises(audioop.error, audioop.mul, data, size, 1.0)
self.assertRaises(audioop.error, audioop.tomono, data, size, 0.5, 0.5)
self.assertRaises(audioop.error, audioop.tostereo, data, size, 0.5, 0.5)
self.assertRaises(audioop.error, audioop.add, data, data, size)
self.assertRaises(audioop.error, audioop.bias, data, size, 0)
self.assertRaises(audioop.error, audioop.reverse, data, size)
self.assertRaises(audioop.error, audioop.lin2lin, data, size, size2)
self.assertRaises(audioop.error, audioop.ratecv, data, size, 1, 1, 1, state)
self.assertRaises(audioop.error, audioop.lin2ulaw, data, size)
self.assertRaises(audioop.error, audioop.ulaw2lin, data, size)
self.assertRaises(audioop.error, audioop.lin2alaw, data, size)
self.assertRaises(audioop.error, audioop.alaw2lin, data, size)
self.assertRaises(audioop.error, audioop.lin2adpcm, data, size, state)
self.assertRaises(audioop.error, audioop.adpcm2lin, data, size, state)
def test_main(): def test_main():
run_unittest(TestAudioop) run_unittest(TestAudioop)

View File

@ -468,13 +468,16 @@ C-API
Library Library
------- -------
- Issue #7673: Fix security vulnerability (CVE-2010-2089) in the audioop
module, ensure that the input string length is a multiple of the frame size
- Issue #6507: Accept source strings in dis.dis(). Original patch by - Issue #6507: Accept source strings in dis.dis(). Original patch by
Daniel Urban. Daniel Urban.
- Issue #7829: Clearly document that the dis module is exposing an - Issue #7829: Clearly document that the dis module is exposing an
implementation detail that is not stable between Python VMs or releases. implementation detail that is not stable between Python VMs or releases.
- Issue #6589: cleanup asyncore.socket_map in case smtpd.SMTPServer constructor - Issue #6589: cleanup asyncore.socket_map in case smtpd.SMTPServer constructor
raises an exception. raises an exception.
- Issue #9110: Addition of ContextDecorator to contextlib, for creating APIs - Issue #9110: Addition of ContextDecorator to contextlib, for creating APIs

View File

@ -297,6 +297,29 @@ static int stepsizeTable[89] = {
static PyObject *AudioopError; 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 * static PyObject *
audioop_getsample(PyObject *self, PyObject *args) audioop_getsample(PyObject *self, PyObject *args)
{ {
@ -306,10 +329,8 @@ audioop_getsample(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#in:getsample", &cp, &len, &size, &i) ) if ( !PyArg_ParseTuple(args, "s#in:getsample", &cp, &len, &size, &i) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
if ( i < 0 || i >= len/size ) { if ( i < 0 || i >= len/size ) {
PyErr_SetString(AudioopError, "Index out of range"); PyErr_SetString(AudioopError, "Index out of range");
return 0; return 0;
@ -330,10 +351,8 @@ audioop_max(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
for ( i=0; i<len; i+= size) { for ( i=0; i<len; i+= size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); if ( size == 1 ) val = (int)*CHARP(cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); else if ( size == 2 ) val = (int)*SHORTP(cp, i);
@ -354,10 +373,8 @@ audioop_minmax(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size)) if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size))
return NULL; return NULL;
if (size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
return NULL; return NULL;
}
for (i = 0; i < len; i += size) { for (i = 0; i < len; i += size) {
if (size == 1) val = (int) *CHARP(cp, i); if (size == 1) val = (int) *CHARP(cp, i);
else if (size == 2) val = (int) *SHORTP(cp, i); else if (size == 2) val = (int) *SHORTP(cp, i);
@ -378,10 +395,8 @@ audioop_avg(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#i:avg", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:avg", &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
for ( i=0; i<len; i+= size) { for ( i=0; i<len; i+= size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); if ( size == 1 ) val = (int)*CHARP(cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); else if ( size == 2 ) val = (int)*SHORTP(cp, i);
@ -405,10 +420,8 @@ audioop_rms(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#i:rms", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:rms", &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
for ( i=0; i<len; i+= size) { for ( i=0; i<len; i+= size) {
if ( size == 1 ) val = (int)*CHARP(cp, i); if ( size == 1 ) val = (int)*CHARP(cp, i);
else if ( size == 2 ) val = (int)*SHORTP(cp, i); else if ( size == 2 ) val = (int)*SHORTP(cp, i);
@ -616,10 +629,8 @@ audioop_avgpp(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#i:avgpp", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:avgpp", &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
/* Compute first delta value ahead. Also automatically makes us /* Compute first delta value ahead. Also automatically makes us
** skip the first extreme value ** skip the first extreme value
*/ */
@ -673,10 +684,8 @@ audioop_maxpp(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#i:maxpp", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:maxpp", &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
/* Compute first delta value ahead. Also automatically makes us /* Compute first delta value ahead. Also automatically makes us
** skip the first extreme value ** skip the first extreme value
*/ */
@ -725,10 +734,8 @@ audioop_cross(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#i:cross", &cp, &len, &size) ) if ( !PyArg_ParseTuple(args, "s#i:cross", &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
ncross = -1; ncross = -1;
prevval = 17; /* Anything <> 0,1 */ prevval = 17; /* Anything <> 0,1 */
for ( i=0; i<len; i+= size) { for ( i=0; i<len; i+= size) {
@ -753,6 +760,8 @@ audioop_mul(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) ) if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) )
return 0; return 0;
if (!audioop_check_parameters(len, size))
return NULL;
if ( size == 1 ) maxval = (double) 0x7f; if ( size == 1 ) maxval = (double) 0x7f;
else if ( size == 2 ) maxval = (double) 0x7fff; else if ( size == 2 ) maxval = (double) 0x7fff;
@ -798,6 +807,12 @@ audioop_tomono(PyObject *self, PyObject *args)
return 0; return 0;
cp = pcp.buf; cp = pcp.buf;
len = pcp.len; len = pcp.len;
if (!audioop_check_parameters(len, size))
return NULL;
if (((len / size) & 1) != 0) {
PyErr_SetString(AudioopError, "not a whole number of frames");
return NULL;
}
if ( size == 1 ) maxval = (double) 0x7f; if ( size == 1 ) maxval = (double) 0x7f;
else if ( size == 2 ) maxval = (double) 0x7fff; else if ( size == 2 ) maxval = (double) 0x7fff;
@ -845,6 +860,8 @@ audioop_tostereo(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#idd:tostereo", if ( !PyArg_ParseTuple(args, "s#idd:tostereo",
&cp, &len, &size, &fac1, &fac2 ) ) &cp, &len, &size, &fac1, &fac2 ) )
return 0; return 0;
if (!audioop_check_parameters(len, size))
return NULL;
if ( size == 1 ) maxval = (double) 0x7f; if ( size == 1 ) maxval = (double) 0x7f;
else if ( size == 2 ) maxval = (double) 0x7fff; else if ( size == 2 ) maxval = (double) 0x7fff;
@ -903,7 +920,8 @@ audioop_add(PyObject *self, PyObject *args)
if ( !PyArg_ParseTuple(args, "s#s#i:add", if ( !PyArg_ParseTuple(args, "s#s#i:add",
&cp1, &len1, &cp2, &len2, &size ) ) &cp1, &len1, &cp2, &len2, &size ) )
return 0; return 0;
if (!audioop_check_parameters(len1, size))
return NULL;
if ( len1 != len2 ) { if ( len1 != len2 ) {
PyErr_SetString(AudioopError, "Lengths should be the same"); PyErr_SetString(AudioopError, "Lengths should be the same");
return 0; return 0;
@ -958,10 +976,8 @@ audioop_bias(PyObject *self, PyObject *args)
&cp, &len, &size , &bias) ) &cp, &len, &size , &bias) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
rv = PyBytes_FromStringAndSize(NULL, len); rv = PyBytes_FromStringAndSize(NULL, len);
if ( rv == 0 ) if ( rv == 0 )
@ -994,10 +1010,8 @@ audioop_reverse(PyObject *self, PyObject *args)
&cp, &len, &size) ) &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4 ) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
rv = PyBytes_FromStringAndSize(NULL, len); rv = PyBytes_FromStringAndSize(NULL, len);
if ( rv == 0 ) if ( rv == 0 )
@ -1031,11 +1045,10 @@ audioop_lin2lin(PyObject *self, PyObject *args)
&cp, &len, &size, &size2) ) &cp, &len, &size, &size2) )
return 0; return 0;
if ( (size != 1 && size != 2 && size != 4) || if (!audioop_check_parameters(len, size))
(size2 != 1 && size2 != 2 && size2 != 4)) { return NULL;
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); if (!audioop_check_size(size2))
return 0; return NULL;
}
if (len/size > PY_SSIZE_T_MAX/size2) { if (len/size > PY_SSIZE_T_MAX/size2) {
PyErr_SetString(PyExc_MemoryError, PyErr_SetString(PyExc_MemoryError,
@ -1086,10 +1099,8 @@ audioop_ratecv(PyObject *self, PyObject *args)
&nchannels, &inrate, &outrate, &state, &nchannels, &inrate, &outrate, &state,
&weightA, &weightB)) &weightA, &weightB))
return NULL; return NULL;
if (size != 1 && size != 2 && size != 4) { if (!audioop_check_size(size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
return NULL; return NULL;
}
if (nchannels < 1) { if (nchannels < 1) {
PyErr_SetString(AudioopError, "# of channels should be >= 1"); PyErr_SetString(AudioopError, "# of channels should be >= 1");
return NULL; return NULL;
@ -1265,10 +1276,8 @@ audioop_lin2ulaw(PyObject *self, PyObject *args)
&cp, &len, &size) ) &cp, &len, &size) )
return 0 ; return 0 ;
if ( size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
rv = PyBytes_FromStringAndSize(NULL, len/size); rv = PyBytes_FromStringAndSize(NULL, len/size);
if ( rv == 0 ) if ( rv == 0 )
@ -1299,10 +1308,8 @@ audioop_ulaw2lin(PyObject *self, PyObject *args)
&cp, &len, &size) ) &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
if (len > PY_SSIZE_T_MAX/size) { if (len > PY_SSIZE_T_MAX/size) {
PyErr_SetString(PyExc_MemoryError, PyErr_SetString(PyExc_MemoryError,
@ -1338,10 +1345,8 @@ audioop_lin2alaw(PyObject *self, PyObject *args)
&cp, &len, &size) ) &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
rv = PyBytes_FromStringAndSize(NULL, len/size); rv = PyBytes_FromStringAndSize(NULL, len/size);
if ( rv == 0 ) if ( rv == 0 )
@ -1372,10 +1377,8 @@ audioop_alaw2lin(PyObject *self, PyObject *args)
&cp, &len, &size) ) &cp, &len, &size) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
if (len > PY_SSIZE_T_MAX/size) { if (len > PY_SSIZE_T_MAX/size) {
PyErr_SetString(PyExc_MemoryError, PyErr_SetString(PyExc_MemoryError,
@ -1413,11 +1416,8 @@ audioop_lin2adpcm(PyObject *self, PyObject *args)
&cp, &len, &size, &state) ) &cp, &len, &size, &state) )
return 0; return 0;
if (!audioop_check_parameters(len, size))
if ( size != 1 && size != 2 && size != 4) { return NULL;
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4");
return 0;
}
str = PyBytes_FromStringAndSize(NULL, len/(size*2)); str = PyBytes_FromStringAndSize(NULL, len/(size*2));
if ( str == 0 ) if ( str == 0 )
@ -1522,10 +1522,8 @@ audioop_adpcm2lin(PyObject *self, PyObject *args)
&cp, &len, &size, &state) ) &cp, &len, &size, &state) )
return 0; return 0;
if ( size != 1 && size != 2 && size != 4) { if (!audioop_check_parameters(len, size))
PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); return NULL;
return 0;
}
/* Decode state, should have (value, step) */ /* Decode state, should have (value, step) */
if ( state == Py_None ) { if ( state == Py_None ) {