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