oss-fuzz: epsfuzzer doesn't pass sanity check

Step #5:     #6 0x640b42f in __cxa_throw (/tmp/not-out/epsfuzzer+0x640b42f)
Step #5:     #7 0x5413d9 in SvStream::ReadUInt32(unsigned int&) (/tmp/not-out/epsfuzzer+0x5413d9)
Step #5:     #8 0x1dd29b1 in ipsGraphicImport (/tmp/not-out/epsfuzzer+0x1dd29b1)

Change-Id: Ieab45edabd5f13d07359be558618ff65badfde2e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/108156
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
This commit is contained in:
Caolán McNamara
2020-12-22 13:57:43 +01:00
parent 901e5e7c91
commit e7c76d604a
+188 -177
View File
@@ -592,227 +592,238 @@ ipsGraphicImport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* )
sal_uInt32 nPosWMF = 0;
sal_uInt32 nSizeTIFF = 0;
sal_uInt32 nPosTIFF = 0;
sal_uInt32 nOrigPos = nPSStreamPos = rStream.Tell();
auto nOrigPos = nPSStreamPos = rStream.Tell();
SvStreamEndian nOldFormat = rStream.GetEndian();
rStream.SetEndian( SvStreamEndian::LITTLE );
rStream.ReadUInt32( nSignature );
if ( nSignature == 0xc6d3d0c5 )
try
{
rStream.ReadUInt32( nPSStreamPos ).ReadUInt32( nPSSize ).ReadUInt32( nPosWMF ).ReadUInt32( nSizeWMF );
// first we try to get the metafile grafix
if ( nSizeWMF )
rStream.SetEndian( SvStreamEndian::LITTLE );
rStream.ReadUInt32( nSignature );
if ( nSignature == 0xc6d3d0c5 )
{
if (nPosWMF && checkSeek(rStream, nOrigPos + nPosWMF))
rStream.ReadUInt32( nPSStreamPos ).ReadUInt32( nPSSize ).ReadUInt32( nPosWMF ).ReadUInt32( nSizeWMF );
// first we try to get the metafile grafix
if ( nSizeWMF )
{
if (GraphicConverter::Import(rStream, aGraphic, ConvertDataFormat::WMF) == ERRCODE_NONE)
bHasPreview = bRetValue = true;
if (nPosWMF && checkSeek(rStream, nOrigPos + nPosWMF))
{
if (GraphicConverter::Import(rStream, aGraphic, ConvertDataFormat::WMF) == ERRCODE_NONE)
bHasPreview = bRetValue = true;
}
}
else
{
rStream.ReadUInt32( nPosTIFF ).ReadUInt32( nSizeTIFF );
// else we have to get the tiff grafix
if (nPosTIFF && nSizeTIFF && checkSeek(rStream, nOrigPos + nPosTIFF))
{
if ( GraphicConverter::Import( rStream, aGraphic, ConvertDataFormat::TIF ) == ERRCODE_NONE )
{
MakeAsMeta(aGraphic);
rStream.Seek( nOrigPos + nPosTIFF );
bHasPreview = bRetValue = true;
}
}
}
}
else
{
rStream.ReadUInt32( nPosTIFF ).ReadUInt32( nSizeTIFF );
// else we have to get the tiff grafix
if (nPosTIFF && nSizeTIFF && checkSeek(rStream, nOrigPos + nPosTIFF))
{
if ( GraphicConverter::Import( rStream, aGraphic, ConvertDataFormat::TIF ) == ERRCODE_NONE )
{
MakeAsMeta(aGraphic);
rStream.Seek( nOrigPos + nPosTIFF );
bHasPreview = bRetValue = true;
}
}
nPSStreamPos = nOrigPos; // no preview available _>so we must get the size manually
nPSSize = rStream.Seek( STREAM_SEEK_TO_END ) - nOrigPos;
}
}
else
{
nPSStreamPos = nOrigPos; // no preview available _>so we must get the size manually
nPSSize = rStream.Seek( STREAM_SEEK_TO_END ) - nOrigPos;
}
std::unique_ptr<sal_uInt8[]> pHeader( new sal_uInt8[ 22 ] );
rStream.Seek( nPSStreamPos );
rStream.ReadBytes(pHeader.get(), 22); // check PostScript header
bool bOk = ImplSearchEntry(pHeader.get(), reinterpret_cast<sal_uInt8 const *>("%!PS-Adobe"), 10, 10) &&
ImplSearchEntry(&pHeader[ 15 ], reinterpret_cast<sal_uInt8 const *>("EPS"), 3, 3);
if (bOk)
{
rStream.Seek(nPSStreamPos);
bOk = rStream.remainingSize() >= nPSSize;
SAL_WARN_IF(!bOk, "filter.eps", "eps claims to be: " << nPSSize << " in size, but only " << rStream.remainingSize() << " remains");
}
if (bOk)
{
std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nPSSize ] );
sal_uInt32 nBufStartPos = rStream.Tell();
sal_uInt32 nBytesRead = rStream.ReadBytes(pBuf.get(), nPSSize);
if ( nBytesRead == nPSSize )
std::unique_ptr<sal_uInt8[]> pHeader( new sal_uInt8[ 22 ] );
rStream.Seek( nPSStreamPos );
rStream.ReadBytes(pHeader.get(), 22); // check PostScript header
bool bOk = ImplSearchEntry(pHeader.get(), reinterpret_cast<sal_uInt8 const *>("%!PS-Adobe"), 10, 10) &&
ImplSearchEntry(&pHeader[ 15 ], reinterpret_cast<sal_uInt8 const *>("EPS"), 3, 3);
if (bOk)
{
sal_uInt32 nSecurityCount = 32;
// if there is no tiff/wmf preview, we will parse for a preview in
// the eps prolog
if (!bHasPreview && nBytesRead >= nSecurityCount)
{
sal_uInt8* pDest = ImplSearchEntry( pBuf.get(), reinterpret_cast<sal_uInt8 const *>("%%BeginPreview:"), nBytesRead - nSecurityCount, 15 );
sal_uInt32 nRemainingBytes = pDest ? (nBytesRead - (pDest - pBuf.get())) : 0;
if (nRemainingBytes >= 15)
{
pDest += 15;
nSecurityCount = nRemainingBytes - 15;
tools::Long nWidth = ImplGetNumber(pDest, nSecurityCount);
tools::Long nHeight = ImplGetNumber(pDest, nSecurityCount);
tools::Long nBitDepth = ImplGetNumber(pDest, nSecurityCount);
tools::Long nScanLines = ImplGetNumber(pDest, nSecurityCount);
pDest = ImplSearchEntry(pDest, reinterpret_cast<sal_uInt8 const *>("%"), nSecurityCount, 1); // go to the first Scanline
bOk = pDest && nWidth > 0 && nHeight > 0 && ( ( nBitDepth == 1 ) || ( nBitDepth == 8 ) ) && nScanLines;
if (bOk)
{
tools::Long nResult;
bOk = !o3tl::checked_multiply(nWidth, nHeight, nResult) && nResult <= SAL_MAX_INT32/2/3;
}
if (bOk)
{
rStream.Seek( nBufStartPos + ( pDest - pBuf.get() ) );
rStream.Seek(nPSStreamPos);
bOk = rStream.remainingSize() >= nPSSize;
SAL_WARN_IF(!bOk, "filter.eps", "eps claims to be: " << nPSSize << " in size, but only " << rStream.remainingSize() << " remains");
}
if (bOk)
{
std::unique_ptr<sal_uInt8[]> pBuf( new sal_uInt8[ nPSSize ] );
vcl::bitmap::RawBitmap aBitmap( Size( nWidth, nHeight ), 24 );
sal_uInt32 nBufStartPos = rStream.Tell();
sal_uInt32 nBytesRead = rStream.ReadBytes(pBuf.get(), nPSSize);
if ( nBytesRead == nPSSize )
{
sal_uInt32 nSecurityCount = 32;
// if there is no tiff/wmf preview, we will parse for a preview in
// the eps prolog
if (!bHasPreview && nBytesRead >= nSecurityCount)
{
sal_uInt8* pDest = ImplSearchEntry( pBuf.get(), reinterpret_cast<sal_uInt8 const *>("%%BeginPreview:"), nBytesRead - nSecurityCount, 15 );
sal_uInt32 nRemainingBytes = pDest ? (nBytesRead - (pDest - pBuf.get())) : 0;
if (nRemainingBytes >= 15)
{
pDest += 15;
nSecurityCount = nRemainingBytes - 15;
tools::Long nWidth = ImplGetNumber(pDest, nSecurityCount);
tools::Long nHeight = ImplGetNumber(pDest, nSecurityCount);
tools::Long nBitDepth = ImplGetNumber(pDest, nSecurityCount);
tools::Long nScanLines = ImplGetNumber(pDest, nSecurityCount);
pDest = ImplSearchEntry(pDest, reinterpret_cast<sal_uInt8 const *>("%"), nSecurityCount, 1); // go to the first Scanline
bOk = pDest && nWidth > 0 && nHeight > 0 && ( ( nBitDepth == 1 ) || ( nBitDepth == 8 ) ) && nScanLines;
if (bOk)
{
bool bIsValid = true;
sal_uInt8 nDat = 0;
char nByte;
for (tools::Long y = 0; bIsValid && y < nHeight; ++y)
tools::Long nResult;
bOk = !o3tl::checked_multiply(nWidth, nHeight, nResult) && nResult <= SAL_MAX_INT32/2/3;
}
if (bOk)
{
rStream.Seek( nBufStartPos + ( pDest - pBuf.get() ) );
vcl::bitmap::RawBitmap aBitmap( Size( nWidth, nHeight ), 24 );
{
int nBitsLeft = 0;
for (tools::Long x = 0; x < nWidth; ++x)
bool bIsValid = true;
sal_uInt8 nDat = 0;
char nByte;
for (tools::Long y = 0; bIsValid && y < nHeight; ++y)
{
if ( --nBitsLeft < 0 )
int nBitsLeft = 0;
for (tools::Long x = 0; x < nWidth; ++x)
{
while ( bIsValid && ( nBitsLeft != 7 ) )
if ( --nBitsLeft < 0 )
{
rStream.ReadChar(nByte);
bIsValid = rStream.good();
if (!bIsValid)
break;
switch (nByte)
while ( bIsValid && ( nBitsLeft != 7 ) )
{
case 0x0a :
if ( --nScanLines < 0 )
bIsValid = false;
rStream.ReadChar(nByte);
bIsValid = rStream.good();
if (!bIsValid)
break;
case 0x09 :
case 0x0d :
case 0x20 :
case 0x25 :
break;
default:
switch (nByte)
{
if ( nByte >= '0' )
case 0x0a :
if ( --nScanLines < 0 )
bIsValid = false;
break;
case 0x09 :
case 0x0d :
case 0x20 :
case 0x25 :
break;
default:
{
if ( nByte > '9' )
if ( nByte >= '0' )
{
nByte &=~0x20; // case none sensitive for hexadecimal values
nByte -= ( 'A' - 10 );
if ( nByte > 15 )
bIsValid = false;
if ( nByte > '9' )
{
nByte &=~0x20; // case none sensitive for hexadecimal values
nByte -= ( 'A' - 10 );
if ( nByte > 15 )
bIsValid = false;
}
else
nByte -= '0';
nBitsLeft += 4;
nDat <<= 4;
nDat |= ( nByte ^ 0xf ); // in epsi a zero bit represents white color
}
else
nByte -= '0';
nBitsLeft += 4;
nDat <<= 4;
nDat |= ( nByte ^ 0xf ); // in epsi a zero bit represents white color
bIsValid = false;
}
else
bIsValid = false;
break;
}
break;
}
}
}
if (!bIsValid)
break;
if ( nBitDepth == 1 )
aBitmap.SetPixel( y, x, Color(static_cast<sal_uInt8>(nDat >> nBitsLeft) & 1) );
else
{
aBitmap.SetPixel( y, x, nDat ? COL_WHITE : COL_BLACK ); // nBitDepth == 8
nBitsLeft = 0;
if (!bIsValid)
break;
if ( nBitDepth == 1 )
aBitmap.SetPixel( y, x, Color(static_cast<sal_uInt8>(nDat >> nBitsLeft) & 1) );
else
{
aBitmap.SetPixel( y, x, nDat ? COL_WHITE : COL_BLACK ); // nBitDepth == 8
nBitsLeft = 0;
}
}
}
}
if (bIsValid)
{
ScopedVclPtrInstance<VirtualDevice> pVDev;
GDIMetaFile aMtf;
Size aSize( nWidth, nHeight );
pVDev->EnableOutput( false );
aMtf.Record( pVDev );
aSize = OutputDevice::LogicToLogic(aSize, MapMode(), MapMode(MapUnit::Map100thMM));
pVDev->DrawBitmapEx( Point(), aSize, vcl::bitmap::CreateFromData(std::move(aBitmap)) );
aMtf.Stop();
aMtf.WindStart();
aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
aMtf.SetPrefSize( aSize );
aGraphic = aMtf;
bHasPreview = bRetValue = true;
if (bIsValid)
{
ScopedVclPtrInstance<VirtualDevice> pVDev;
GDIMetaFile aMtf;
Size aSize( nWidth, nHeight );
pVDev->EnableOutput( false );
aMtf.Record( pVDev );
aSize = OutputDevice::LogicToLogic(aSize, MapMode(), MapMode(MapUnit::Map100thMM));
pVDev->DrawBitmapEx( Point(), aSize, vcl::bitmap::CreateFromData(std::move(aBitmap)) );
aMtf.Stop();
aMtf.WindStart();
aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
aMtf.SetPrefSize( aSize );
aGraphic = aMtf;
bHasPreview = bRetValue = true;
}
}
}
}
}
}
sal_uInt8* pDest = ImplSearchEntry( pBuf.get(), reinterpret_cast<sal_uInt8 const *>("%%BoundingBox:"), nBytesRead, 14 );
sal_uInt32 nRemainingBytes = pDest ? (nBytesRead - (pDest - pBuf.get())) : 0;
if (nRemainingBytes >= 14)
{
pDest += 14;
nSecurityCount = std::min<sal_uInt32>(nRemainingBytes - 14, 100);
tools::Long nNumb[4];
nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
sal_uInt8* pDest = ImplSearchEntry( pBuf.get(), reinterpret_cast<sal_uInt8 const *>("%%BoundingBox:"), nBytesRead, 14 );
sal_uInt32 nRemainingBytes = pDest ? (nBytesRead - (pDest - pBuf.get())) : 0;
if (nRemainingBytes >= 14)
{
nNumb[ i ] = ImplGetNumber(pDest, nSecurityCount);
}
bool bFail = nSecurityCount == 0;
tools::Long nWidth(0), nHeight(0);
if (!bFail)
bFail = o3tl::checked_sub(nNumb[2], nNumb[0], nWidth) || o3tl::checked_add(nWidth, tools::Long(1), nWidth);
if (!bFail)
bFail = o3tl::checked_sub(nNumb[3], nNumb[1], nHeight) || o3tl::checked_add(nHeight, tools::Long(1), nHeight);
if (!bFail && nWidth > 0 && nHeight > 0)
{
GDIMetaFile aMtf;
// if there is no preview -> try with gs to make one
if (!bHasPreview && !utl::ConfigManager::IsFuzzing())
pDest += 14;
nSecurityCount = std::min<sal_uInt32>(nRemainingBytes - 14, 100);
tools::Long nNumb[4];
nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
{
bHasPreview = RenderAsEMF(pBuf.get(), nBytesRead, aGraphic);
if (!bHasPreview)
bHasPreview = RenderAsBMP(pBuf.get(), nBytesRead, aGraphic);
nNumb[ i ] = ImplGetNumber(pDest, nSecurityCount);
}
// if there is no preview -> make a red box
if( !bHasPreview )
bool bFail = nSecurityCount == 0;
tools::Long nWidth(0), nHeight(0);
if (!bFail)
bFail = o3tl::checked_sub(nNumb[2], nNumb[0], nWidth) || o3tl::checked_add(nWidth, tools::Long(1), nWidth);
if (!bFail)
bFail = o3tl::checked_sub(nNumb[3], nNumb[1], nHeight) || o3tl::checked_add(nHeight, tools::Long(1), nHeight);
if (!bFail && nWidth > 0 && nHeight > 0)
{
MakePreview(pBuf.get(), nBytesRead, nWidth, nHeight,
aGraphic);
}
GDIMetaFile aMtf;
GfxLink aGfxLink( std::move(pBuf), nPSSize, GfxLinkType::EpsBuffer ) ;
aMtf.AddAction( static_cast<MetaAction*>( new MetaEPSAction( Point(), Size( nWidth, nHeight ),
aGfxLink, aGraphic.GetGDIMetaFile() ) ) );
CreateMtfReplacementAction( aMtf, rStream, nOrigPos, nPSSize, nPosWMF, nSizeWMF, nPosTIFF, nSizeTIFF );
aMtf.WindStart();
aMtf.SetPrefMapMode(MapMode(MapUnit::MapPoint));
aMtf.SetPrefSize( Size( nWidth, nHeight ) );
rGraphic = aMtf;
bRetValue = true;
// if there is no preview -> try with gs to make one
if (!bHasPreview && !utl::ConfigManager::IsFuzzing())
{
bHasPreview = RenderAsEMF(pBuf.get(), nBytesRead, aGraphic);
if (!bHasPreview)
bHasPreview = RenderAsBMP(pBuf.get(), nBytesRead, aGraphic);
}
// if there is no preview -> make a red box
if( !bHasPreview )
{
MakePreview(pBuf.get(), nBytesRead, nWidth, nHeight,
aGraphic);
}
GfxLink aGfxLink( std::move(pBuf), nPSSize, GfxLinkType::EpsBuffer ) ;
aMtf.AddAction( static_cast<MetaAction*>( new MetaEPSAction( Point(), Size( nWidth, nHeight ),
aGfxLink, aGraphic.GetGDIMetaFile() ) ) );
CreateMtfReplacementAction( aMtf, rStream, nOrigPos, nPSSize, nPosWMF, nSizeWMF, nPosTIFF, nSizeTIFF );
aMtf.WindStart();
aMtf.SetPrefMapMode(MapMode(MapUnit::MapPoint));
aMtf.SetPrefSize( Size( nWidth, nHeight ) );
rGraphic = aMtf;
bRetValue = true;
}
}
}
}
}
catch (const SvStreamEOFException&)
{
SAL_WARN("filter.eps", "EOF");
bRetValue = false;
}
rStream.SetEndian(nOldFormat);
rStream.Seek( nOrigPos );
return bRetValue;