Browse Source

Validate WebP metadata chunk lengths

pull/3187/head
James Jackson-South 4 weeks ago
parent
commit
2b52b55be6
  1. 28
      src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs
  2. 10
      tests/ImageSharp.Tests/Formats/WebP/WebpMetaDataTests.cs

28
src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs

@ -355,15 +355,15 @@ internal static class WebpChunkParsingUtils
bool ignoreMetadata)
{
Span<byte> buffer = stackalloc byte[4];
uint iccpChunkSize = ReadChunkSize(stream, buffer);
int iccpChunkSize = ValidateMetadataChunkSize(stream, ReadChunkSize(stream, buffer), "ICCP");
if (ignoreMetadata || metadata.IccProfile != null)
{
stream.Skip((int)iccpChunkSize);
stream.Skip(iccpChunkSize);
}
else
{
byte[] iccpData = new byte[iccpChunkSize];
int bytesRead = stream.Read(iccpData, 0, (int)iccpChunkSize);
int bytesRead = stream.Read(iccpData, 0, iccpChunkSize);
if (bytesRead != iccpChunkSize)
{
WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the iccp chunk");
@ -391,15 +391,15 @@ internal static class WebpChunkParsingUtils
bool ignoreMetadata)
{
Span<byte> buffer = stackalloc byte[4];
uint exifChunkSize = ReadChunkSize(stream, buffer);
int exifChunkSize = ValidateMetadataChunkSize(stream, ReadChunkSize(stream, buffer), "EXIF");
if (ignoreMetadata || metadata.ExifProfile != null)
{
stream.Skip((int)exifChunkSize);
stream.Skip(exifChunkSize);
}
else
{
byte[] exifData = new byte[exifChunkSize];
int bytesRead = stream.Read(exifData, 0, (int)exifChunkSize);
int bytesRead = stream.Read(exifData, 0, exifChunkSize);
if (bytesRead != exifChunkSize)
{
WebpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for the EXIF profile");
@ -434,15 +434,15 @@ internal static class WebpChunkParsingUtils
bool ignoreMetadata)
{
Span<byte> buffer = stackalloc byte[4];
uint xmpChunkSize = ReadChunkSize(stream, buffer);
int xmpChunkSize = ValidateMetadataChunkSize(stream, ReadChunkSize(stream, buffer), "XMP");
if (ignoreMetadata || metadata.XmpProfile != null)
{
stream.Skip((int)xmpChunkSize);
stream.Skip(xmpChunkSize);
}
else
{
byte[] xmpData = new byte[xmpChunkSize];
int bytesRead = stream.Read(xmpData, 0, (int)xmpChunkSize);
int bytesRead = stream.Read(xmpData, 0, xmpChunkSize);
if (bytesRead != xmpChunkSize)
{
WebpThrowHelper.ThrowInvalidImageContentException("Could not read enough data for the XMP profile");
@ -452,6 +452,16 @@ internal static class WebpChunkParsingUtils
}
}
private static int ValidateMetadataChunkSize(BufferedReadStream stream, uint chunkSize, string chunkName)
{
if (chunkSize > int.MaxValue || chunkSize > stream.Length - stream.Position)
{
WebpThrowHelper.ThrowInvalidImageContentException($"Not enough data to read the {chunkName} chunk");
}
return (int)chunkSize;
}
private static double GetExifResolutionValue(ExifProfile exifProfile, ExifTag<Rational> tag)
{
if (exifProfile.TryGetValue(tag, out IExifValue<Rational>? resolution))

10
tests/ImageSharp.Tests/Formats/WebP/WebpMetaDataTests.cs

@ -228,4 +228,14 @@ public class WebpMetaDataTests
using Image<Rgba32> image = Image.Load<Rgba32>(options, stream);
});
}
[Fact]
public void Decode_WithOversizedIccChunk_ThrowsInvalidImageContentException()
{
byte[] payload = Convert.FromHexString(
"524946462200000057454250565038580A0000002000000000000000000049434350FEFFFFFF01020304");
Assert.Throws<InvalidImageContentException>(() => Image.Load(payload));
Assert.Throws<InvalidImageContentException>(() => Image.Identify(payload));
}
}

Loading…
Cancel
Save