Browse Source

Validate ICC CLUT storage before allocation

pull/3187/head
James Jackson-South 4 weeks ago
parent
commit
8de892a762
  1. 48
      src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs
  2. 10
      tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs

48
src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs

@ -72,13 +72,7 @@ internal sealed partial class IccDataReader
/// <returns>The read CLUT8.</returns>
public IccClut ReadClut8(int inChannelCount, int outChannelCount, byte[] gridPointCount)
{
int length = 0;
for (int i = 0; i < inChannelCount; i++)
{
length += (int)Math.Pow(gridPointCount[i], inChannelCount);
}
length /= inChannelCount;
int length = this.GetClutLength(inChannelCount, outChannelCount, gridPointCount, 1);
const float Max = byte.MaxValue;
@ -105,13 +99,7 @@ internal sealed partial class IccDataReader
public IccClut ReadClut16(int inChannelCount, int outChannelCount, byte[] gridPointCount)
{
int start = this.currentIndex;
int length = 0;
for (int i = 0; i < inChannelCount; i++)
{
length += (int)Math.Pow(gridPointCount[i], inChannelCount);
}
length /= inChannelCount;
int length = this.GetClutLength(inChannelCount, outChannelCount, gridPointCount, 2);
const float Max = ushort.MaxValue;
@ -139,13 +127,7 @@ internal sealed partial class IccDataReader
public IccClut ReadClutF32(int inChCount, int outChCount, byte[] gridPointCount)
{
int start = this.currentIndex;
int length = 0;
for (int i = 0; i < inChCount; i++)
{
length += (int)Math.Pow(gridPointCount[i], inChCount);
}
length /= inChCount;
int length = this.GetClutLength(inChCount, outChCount, gridPointCount, 4);
float[] values = new float[length * outChCount];
int offset = 0;
@ -160,4 +142,28 @@ internal sealed partial class IccDataReader
this.currentIndex = start + (length * outChCount * 4);
return new IccClut(values, gridPointCount, IccClutDataType.Float, outChCount);
}
private int GetClutLength(int inputChannelCount, int outputChannelCount, byte[] gridPointCount, int bytesPerValue)
{
int length = 1;
for (int i = 0; i < inputChannelCount; i++)
{
int gridPoints = gridPointCount[i];
if (gridPoints == 0 || length > int.MaxValue / gridPoints)
{
throw new InvalidIccProfileException("Invalid CLUT dimensions.");
}
length *= gridPoints;
}
long valueCount = (long)length * outputChannelCount;
long byteCount = valueCount * bytesPerValue;
if (valueCount > int.MaxValue || byteCount > this.data.Length - this.currentIndex)
{
throw new InvalidIccProfileException("The CLUT data is shorter than its declared dimensions.");
}
return length;
}
}

10
tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs

@ -53,6 +53,16 @@ public class IccDataReaderLutTests
Assert.Equal(expected, output);
}
[Fact]
public void ReadClut_WithOversizedDimensions_ThrowsInvalidIccProfileException()
{
byte[] gridPointCount = Enumerable.Repeat((byte)3, 15).ToArray();
Assert.Throws<InvalidIccProfileException>(() => CreateReader(new byte[8]).ReadClut8(15, 15, gridPointCount));
Assert.Throws<InvalidIccProfileException>(() => CreateReader(new byte[8]).ReadClut16(15, 15, gridPointCount));
Assert.Throws<InvalidIccProfileException>(() => CreateReader(new byte[8]).ReadClutF32(15, 15, gridPointCount));
}
[Theory]
[MemberData(nameof(IccTestDataLut.Lut8TestData), MemberType = typeof(IccTestDataLut))]
internal void ReadLut8(byte[] data, IccLut expected)

Loading…
Cancel
Save