diff --git a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs
index 700e43f972..da2f37efd3 100644
--- a/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs
+++ b/src/ImageSharp/Metadata/Profiles/ICC/DataReader/IccDataReader.Lut.cs
@@ -72,13 +72,7 @@ internal sealed partial class IccDataReader
/// The read CLUT8.
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;
+ }
}
diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs
index a686d44872..055756e96b 100644
--- a/tests/ImageSharp.Tests/Metadata/Profiles/ICC/DataReader/IccDataReaderLutTests.cs
+++ b/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(() => CreateReader(new byte[8]).ReadClut8(15, 15, gridPointCount));
+ Assert.Throws(() => CreateReader(new byte[8]).ReadClut16(15, 15, gridPointCount));
+ Assert.Throws(() => CreateReader(new byte[8]).ReadClutF32(15, 15, gridPointCount));
+ }
+
[Theory]
[MemberData(nameof(IccTestDataLut.Lut8TestData), MemberType = typeof(IccTestDataLut))]
internal void ReadLut8(byte[] data, IccLut expected)