Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be 3660 CVE 2017 18207 #43

Merged
merged 2 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions Lib/aifc.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@
"""

import struct
import warnings
import __builtin__

__all__ = ["Error","open","openfp"]
Expand Down Expand Up @@ -316,16 +317,16 @@ def initfp(self, file):
except EOFError:
break
chunkname = chunk.getname()
if chunkname == 'COMM':
if chunkname == b'COMM':
self._read_comm_chunk(chunk)
self._comm_chunk_read = 1
elif chunkname == 'SSND':
elif chunkname == b'SSND':
self._ssnd_chunk = chunk
dummy = chunk.read(8)
self._ssnd_seek_needed = 0
elif chunkname == 'FVER':
elif chunkname == b'FVER':
self._version = _read_ulong(chunk)
elif chunkname == 'MARK':
elif chunkname == b'MARK':
self._readmark(chunk)
chunk.skip()
if not self._comm_chunk_read or not self._ssnd_chunk:
Expand Down Expand Up @@ -465,13 +466,18 @@ def _read_comm_chunk(self, chunk):
self._nframes = _read_long(chunk)
self._sampwidth = (_read_short(chunk) + 7) // 8
self._framerate = int(_read_float(chunk))
if self._sampwidth <= 0:
raise Error, 'bad sample width'
if self._nchannels <= 0:
raise Error, 'bad # of channels'

self._framesize = self._nchannels * self._sampwidth
if self._aifc:
#DEBUG: SGI's soundeditor produces a bad size :-(
kludge = 0
if chunk.chunksize == 18:
kludge = 1
print 'Warning: bad COMM chunk size'
warnings.warn("bad COMM chunk size")
chunk.chunksize = 23
#DEBUG end
self._comptype = chunk.read(4)
Expand Down Expand Up @@ -535,11 +541,13 @@ def _readmark(self, chunk):
# a position 0 and name ''
self._markers.append((id, pos, name))
except EOFError:
print 'Warning: MARK chunk contains only',
print len(self._markers),
if len(self._markers) == 1: print 'marker',
else: print 'markers',
print 'instead of', nmarkers
warning_message = 'MARK chunk contains only ' + str(len(self._markers))
if len(self._markers) == 1:
warning_message += ' marker '
else:
warning_message += ' markers '
warning_message += 'instead of ' + str(nmarkers)
warnings.warn(warning_message)

class Aifc_write:
# Variables used in this class:
Expand Down
2 changes: 2 additions & 0 deletions Lib/sunau.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ def initfp(self, file):
raise Error, 'unknown encoding'
self._framerate = int(_read_u32(file))
self._nchannels = int(_read_u32(file))
if not self._nchannels:
raise Error('bad # of channels')
self._framesize = self._framesize * self._nchannels
if self._hdr_size > 24:
self._info = file.read(self._hdr_size - 24)
Expand Down
70 changes: 46 additions & 24 deletions Lib/test/test_aifc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import sys
import struct
import aifc
from test.test_support import check_warnings


class AifcTest(audiotests.AudioWriteTests,
Expand Down Expand Up @@ -216,47 +217,68 @@ def test_read_no_comm_chunk(self):

def test_read_no_ssnd_chunk(self):
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 38, 0, 0, 0, 0, 0, 0)
b += b'COMM' + struct.pack('>LhlhhLL', 38, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00'
with self.assertRaisesRegexp(aifc.Error, 'COMM chunk and/or SSND chunk'
' missing'):
aifc.open(io.BytesIO(b))

def test_read_wrong_compression_type(self):
b = 'FORM' + struct.pack('>L', 4) + 'AIFC'
b += 'COMM' + struct.pack('>LhlhhLL', 23, 0, 0, 0, 0, 0, 0)
b += 'WRNG' + struct.pack('B', 0)
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 23, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'WRNG' + struct.pack('B', 0)
self.assertRaises(aifc.Error, aifc.open, io.BytesIO(b))

def test_read_wrong_number_of_channels(self):
for nchannels in 0, -1:
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 38, nchannels, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with self.assertRaisesRegexp(aifc.Error, 'bad # of channels'):
aifc.open(io.BytesIO(b))

def test_read_wrong_sample_width(self):
for sampwidth in 0, -1:
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 38, 1, 0, sampwidth,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 14) + b'not compressed' + b'\x00'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with self.assertRaisesRegexp(aifc.Error, 'bad sample width'):
aifc.open(io.BytesIO(b))

def test_read_wrong_marks(self):
b = 'FORM' + struct.pack('>L', 4) + 'AIFF'
b += 'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
b += 'SSND' + struct.pack('>L', 8) + '\x00' * 8
b += 'MARK' + struct.pack('>LhB', 3, 1, 1)
with captured_stdout() as s:
b = b'FORM' + struct.pack('>L', 4) + b'AIFF'
b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
b += b'MARK' + struct.pack('>LhB', 3, 1, 1)
with check_warnings(('MARK chunk contains only 0 markers instead of 1', UserWarning)):
f = aifc.open(io.BytesIO(b))
self.assertEqual(s.getvalue(), 'Warning: MARK chunk contains '
'only 0 markers instead of 1\n')
self.assertEqual(f.getmarkers(), None)
self.assertEqual(f.getmarkers(), None)

def test_read_comm_kludge_compname_even(self):
b = 'FORM' + struct.pack('>L', 4) + 'AIFC'
b += 'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
b += 'NONE' + struct.pack('B', 4) + 'even' + '\x00'
b += 'SSND' + struct.pack('>L', 8) + '\x00' * 8
with captured_stdout() as s:
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 4) + b'even' + b'\x00'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with check_warnings(('bad COMM chunk size', UserWarning)):
f = aifc.open(io.BytesIO(b))
self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n')
self.assertEqual(f.getcompname(), 'even')

def test_read_comm_kludge_compname_odd(self):
b = 'FORM' + struct.pack('>L', 4) + 'AIFC'
b += 'COMM' + struct.pack('>LhlhhLL', 18, 0, 0, 0, 0, 0, 0)
b += 'NONE' + struct.pack('B', 3) + 'odd'
b += 'SSND' + struct.pack('>L', 8) + '\x00' * 8
with captured_stdout() as s:
b = b'FORM' + struct.pack('>L', 4) + b'AIFC'
b += b'COMM' + struct.pack('>LhlhhLL', 18, 1, 0, 8,
0x4000 | 12, 11025<<18, 0)
b += b'NONE' + struct.pack('B', 3) + b'odd'
b += b'SSND' + struct.pack('>L', 8) + b'\x00' * 8
with check_warnings(('bad COMM chunk size', UserWarning)):
f = aifc.open(io.BytesIO(b))
self.assertEqual(s.getvalue(), 'Warning: bad COMM chunk size\n')
self.assertEqual(f.getcompname(), 'odd')

def test_write_params_raises(self):
Expand Down
38 changes: 38 additions & 0 deletions Lib/test/test_sunau.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from test.test_support import TESTFN, run_unittest
import unittest
from test import audiotests
import io
import struct
import sys
import sunau

Expand Down Expand Up @@ -96,5 +98,41 @@ def test_main():
run_unittest(SunauPCM8Test, SunauPCM16Test, SunauPCM16Test,
SunauPCM32Test, SunauULAWTest)


class SunauLowLevelTest(unittest.TestCase):

def test_read_bad_magic_number(self):
b = b'SPA'
with self.assertRaises(EOFError):
sunau.open(io.BytesIO(b))
b = b'SPAM'
with self.assertRaisesRegex(sunau.Error, 'bad magic number'):
sunau.open(io.BytesIO(b))

def test_read_too_small_header(self):
b = struct.pack('>LLLLL', sunau.AUDIO_FILE_MAGIC, 20, 0,
sunau.AUDIO_FILE_ENCODING_LINEAR_8, 11025)
with self.assertRaisesRegex(sunau.Error, 'header size too small'):
sunau.open(io.BytesIO(b))

def test_read_too_large_header(self):
b = struct.pack('>LLLLLL', sunau.AUDIO_FILE_MAGIC, 124, 0,
sunau.AUDIO_FILE_ENCODING_LINEAR_8, 11025, 1)
b += b'\0' * 100
with self.assertRaisesRegex(sunau.Error, 'header size ridiculously large'):
sunau.open(io.BytesIO(b))

def test_read_wrong_encoding(self):
b = struct.pack('>LLLLLL', sunau.AUDIO_FILE_MAGIC, 24, 0, 0, 11025, 1)
with self.assertRaisesRegex(sunau.Error, r'encoding not \(yet\) supported'):
sunau.open(io.BytesIO(b))

def test_read_wrong_number_of_channels(self):
b = struct.pack('>LLLLLL', sunau.AUDIO_FILE_MAGIC, 24, 0,
sunau.AUDIO_FILE_ENCODING_LINEAR_8, 11025, 0)
with self.assertRaisesRegex(sunau.Error, 'bad # of channels'):
sunau.open(io.BytesIO(b))


if __name__ == "__main__":
test_main()
64 changes: 64 additions & 0 deletions Lib/test/test_wave.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from test.test_support import TESTFN, run_unittest
import unittest
from test import audiotests
from test import support
import io
import struct
import sys
import wave

Expand Down Expand Up @@ -119,5 +122,66 @@ def test_unseekable_incompleted_write(self):
def test_main():
run_unittest(WavePCM8Test, WavePCM16Test, WavePCM24Test, WavePCM32Test)


class WaveLowLevelTest(unittest.TestCase):

def test_read_no_chunks(self):
b = b'SPAM'
with self.assertRaises(EOFError):
wave.open(io.BytesIO(b))

def test_read_no_riff_chunk(self):
b = b'SPAM' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error,
'file does not start with RIFF id'):
wave.open(io.BytesIO(b))

def test_read_not_wave(self):
b = b'RIFF' + struct.pack('<L', 4) + b'SPAM'
with self.assertRaisesRegex(wave.Error,
'not a WAVE file'):
wave.open(io.BytesIO(b))

def test_read_no_fmt_no_data_chunk(self):
b = b'RIFF' + struct.pack('<L', 4) + b'WAVE'
with self.assertRaisesRegex(wave.Error,
'fmt chunk and/or data chunk missing'):
wave.open(io.BytesIO(b))

def test_read_no_data_chunk(self):
b = b'RIFF' + struct.pack('<L', 28) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 1, 11025, 11025, 1, 8)
with self.assertRaisesRegex(wave.Error,
'fmt chunk and/or data chunk missing'):
wave.open(io.BytesIO(b))

def test_read_no_fmt_chunk(self):
b = b'RIFF' + struct.pack('<L', 12) + b'WAVE'
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'data chunk before fmt chunk'):
wave.open(io.BytesIO(b))

def test_read_wrong_form(self):
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 2, 1, 11025, 11025, 1, 1)
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'unknown format: 2'):
wave.open(io.BytesIO(b))

def test_read_wrong_number_of_channels(self):
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 0, 11025, 11025, 1, 8)
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'bad # of channels'):
wave.open(io.BytesIO(b))

def test_read_wrong_sample_width(self):
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 1, 11025, 11025, 1, 0)
b += b'data' + struct.pack('<L', 0)
with self.assertRaisesRegex(wave.Error, 'bad sample width'):
wave.open(io.BytesIO(b))


if __name__ == '__main__':
test_main()
16 changes: 13 additions & 3 deletions Lib/wave.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,22 @@ def readframes(self, nframes):
#

def _read_fmt_chunk(self, chunk):
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack('<HHLLH', chunk.read(14))
try:
wFormatTag, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14))
except struct.error:
raise EOFError
if wFormatTag == WAVE_FORMAT_PCM:
sampwidth = struct.unpack('<H', chunk.read(2))[0]
try:
sampwidth = struct.unpack_from('<H', chunk.read(2))[0]
except struct.error:
raise EOFError
self._sampwidth = (sampwidth + 7) // 8
if not self._sampwidth:
raise Error('bad sample width')
else:
raise Error, 'unknown format: %r' % (wFormatTag,)
raise Error('unknown format: %r' % (wFormatTag,))
if not self._nchannels:
raise Error('bad # of channels')
self._framesize = self._nchannels * self._sampwidth
self._comptype = 'NONE'
self._compname = 'not compressed'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Improved exceptions raised for invalid number of channels and sample width
when read an audio file in modules :mod:`aifc`, :mod:`wave` and
:mod:`sunau`.