PNGMetadataExtractor: skip oversize chunks instead of aborting
Bug: T286273 Change-Id: Iceaf92647e74a1e20f94fc36822d0735f70764dc
This commit is contained in:
parent
2f69c21326
commit
d0d73ff1f9
2 changed files with 38 additions and 6 deletions
|
|
@ -106,8 +106,13 @@ class PNGMetadataExtractor {
|
|||
$buf = self::read( $fh, 4 );
|
||||
$chunk_size = unpack( "N", $buf )[1];
|
||||
|
||||
if ( $chunk_size < 0 ) {
|
||||
throw new Exception( __METHOD__ . ": Chunk size too big for unpack" );
|
||||
if ( $chunk_size < 0 || $chunk_size > self::MAX_CHUNK_SIZE ) {
|
||||
wfDebug( __METHOD__ . ': Chunk size of ' . $chunk_size .
|
||||
' too big, skipping. Max size is: ' . self::MAX_CHUNK_SIZE );
|
||||
if ( fseek( $fh, 4 + $chunk_size + self::$crcSize, SEEK_CUR ) !== 0 ) {
|
||||
throw new Exception( __METHOD__ . ': seek error' );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$chunk_type = self::read( $fh, 4 );
|
||||
|
|
@ -399,10 +404,6 @@ class PNGMetadataExtractor {
|
|||
* @return string The chunk.
|
||||
*/
|
||||
private static function read( $fh, $size ) {
|
||||
if ( $size > self::MAX_CHUNK_SIZE ) {
|
||||
throw new Exception( __METHOD__ . ': Chunk size of ' . $size .
|
||||
' too big. Max size is: ' . self::MAX_CHUNK_SIZE );
|
||||
}
|
||||
if ( $size === 0 ) {
|
||||
return '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,4 +144,35 @@ class PNGMetadataExtractorTest extends MediaWikiIntegrationTestCase {
|
|||
$this->assertEquals( 10, $meta['width'] );
|
||||
$this->assertEquals( 10, $meta['height'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* T286273 -- oversize chunk
|
||||
*/
|
||||
public function testPngOversizeChunk() {
|
||||
// Write a temporary file consisting of a normal PNG plus an extra tEXt chunk.
|
||||
// Try to hold the chunk in memory only once.
|
||||
$path = $this->getNewTempFile();
|
||||
copy( $this->filePath . '1bit-png.png', $path );
|
||||
$chunkTypeAndData = "tEXtkey\0value" . str_repeat( '.', 10000000 );
|
||||
$crc = crc32( $chunkTypeAndData );
|
||||
$chunkLength = strlen( $chunkTypeAndData ) - 4;
|
||||
$file = fopen( $path, 'r+' );
|
||||
fseek( $file, -12, SEEK_END );
|
||||
$iend = fread( $file, 12 );
|
||||
fseek( $file, -12, SEEK_END );
|
||||
fwrite( $file, pack( 'N', $chunkLength ) );
|
||||
fwrite( $file, $chunkTypeAndData );
|
||||
fwrite( $file, pack( 'N', $crc ) );
|
||||
fwrite( $file, $iend );
|
||||
fclose( $file );
|
||||
|
||||
// Extract the metadata
|
||||
$meta = PNGMetadataExtractor::getMetadata( $path );
|
||||
$this->assertEquals( 50, $meta['width'] );
|
||||
$this->assertEquals( 50, $meta['height'] );
|
||||
|
||||
// Verify that the big chunk didn't end up in the metadata
|
||||
$this->assertLessThan( 100000, strlen( serialize( $meta ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue