Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jpeg Fuzz Fixes #836

Merged
merged 23 commits into from
Feb 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
903e4cd
Nomalize jpeg exceptions. Fix #821
JimBobSquarePants Feb 15, 2019
7fa95ec
Merge branch 'master' into js/jpeg-security
JimBobSquarePants Feb 15, 2019
9823c85
Merge branch 'master' into js/jpeg-security
JimBobSquarePants Feb 15, 2019
925b25d
Fix #822
JimBobSquarePants Feb 15, 2019
fdeb6ea
Fix #823
JimBobSquarePants Feb 16, 2019
9722e81
Check for correct QT index. Touch #824
JimBobSquarePants Feb 16, 2019
af78ccf
Check DHT props. Touch #824
JimBobSquarePants Feb 16, 2019
bf55db7
Limit sampling factors to 1 & 2. Touch #824
JimBobSquarePants Feb 16, 2019
e984f86
Add already fixed image 4. Touch #824
JimBobSquarePants Feb 16, 2019
510c363
Check for excessive code lengths. Touch #824
JimBobSquarePants Feb 16, 2019
9efdcb6
Add already fixed image 6. Touch #824
JimBobSquarePants Feb 16, 2019
8d974c5
Lint progressive scan details. Touch #824
JimBobSquarePants Feb 16, 2019
c405175
Add already fixed image 8. Fix #824
JimBobSquarePants Feb 16, 2019
e4b2cb7
Remove duplicate per-block checks
JimBobSquarePants Feb 16, 2019
6cb10dc
Add already fixed image 1. Touch #825
JimBobSquarePants Feb 16, 2019
d6703d8
Don't throw on bad JFIF density units.
JimBobSquarePants Feb 17, 2019
9bbd69a
Add already fixed image 3. Touch #825
JimBobSquarePants Feb 17, 2019
23b7161
Add already fixed image 4. Fix #825
JimBobSquarePants Feb 17, 2019
e340769
Check SOFn marker length. Touch #826
JimBobSquarePants Feb 17, 2019
cf98f53
Add already fixed image 2. Touch #826
JimBobSquarePants Feb 17, 2019
6f83609
Add already fixed image 3. Fix #826
JimBobSquarePants Feb 17, 2019
caacfc3
Add fixed already fixed image. Fix #827
JimBobSquarePants Feb 17, 2019
1e38243
Revert unneeded bounds check introduced in #804
JimBobSquarePants Feb 17, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,8 @@ internal unsafe struct HuffmanTable
/// <param name="values">The huffman values</param>
public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values)
{
// We do some bounds checks in the code here to protect against AccessViolationExceptions
const int HuffCodeLength = 257;
const int MaxSizeLength = HuffCodeLength - 1;
using (IMemoryOwner<short> huffcode = memoryAllocator.Allocate<short>(HuffCodeLength))
const int Length = 257;
using (IMemoryOwner<short> huffcode = memoryAllocator.Allocate<short>(Length))
{
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths);
Expand All @@ -65,7 +63,7 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
for (short i = 1; i < 17; i++)
{
byte length = Unsafe.Add(ref codeLengthsRef, i);
for (short j = 0; j < length && x < MaxSizeLength; j++)
for (short j = 0; j < length; j++)
{
Unsafe.Add(ref sizesRef, x++) = i;
}
Expand All @@ -86,7 +84,7 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
Unsafe.Add(ref valOffsetRef, k) = (int)(si - code);
if (Unsafe.Add(ref sizesRef, si) == k)
{
while (Unsafe.Add(ref sizesRef, si) == k && si < HuffCodeLength)
while (Unsafe.Add(ref sizesRef, si) == k)
{
Unsafe.Add(ref huffcodeRef, si++) = (short)code++;
}
Expand All @@ -103,19 +101,19 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
// Generate non-spec lookup tables to speed up decoding.
const int FastBits = ScanDecoder.FastBits;
ref byte lookaheadRef = ref this.Lookahead[0];
const uint MaxFastLength = 1 << FastBits;
Unsafe.InitBlockUnaligned(ref lookaheadRef, 0xFF, MaxFastLength); // Flag for non-accelerated
Unsafe.InitBlockUnaligned(ref lookaheadRef, 0xFF, 1 << FastBits); // Flag for non-accelerated

for (int i = 0; i < si; i++)
{
int size = Unsafe.Add(ref sizesRef, i);
if (size <= FastBits)
{
int huffCode = Unsafe.Add(ref huffcodeRef, i) << (FastBits - size);
int max = 1 << (FastBits - size);
for (int left = 0; left < max; left++)
int fastOffset = FastBits - size;
int fastCode = Unsafe.Add(ref huffcodeRef, i) << fastOffset;
int fastMax = 1 << fastOffset;
for (int left = 0; left < fastMax; left++)
{
Unsafe.Add(ref lookaheadRef, huffCode + left) = (byte)i;
Unsafe.Add(ref lookaheadRef, fastCode + left) = (byte)i;
}
}
}
Expand Down
19 changes: 12 additions & 7 deletions src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <param name="yDensity">The vertical pixel density</param>
private JFifMarker(byte majorVersion, byte minorVersion, byte densityUnits, short xDensity, short yDensity)
{
Guard.MustBeGreaterThan(xDensity, 0, nameof(xDensity));
Guard.MustBeGreaterThan(yDensity, 0, nameof(yDensity));
Guard.MustBeBetweenOrEqualTo(densityUnits, 0, 2, nameof(densityUnits));
if (xDensity <= 0)
{
JpegThrowHelper.ThrowImageFormatException($"X-Density {xDensity} must be greater than 0.");
}

if (yDensity <= 0)
{
JpegThrowHelper.ThrowImageFormatException($"Y-Density {yDensity} must be greater than 0.");
}

this.MajorVersion = majorVersion;
this.MinorVersion = minorVersion;

// LibJpeg and co will simply cast and not try to enforce a range.
this.DensityUnits = (PixelResolutionUnit)densityUnits;
this.XDensity = xDensity;
this.YDensity = yDensity;
Expand Down Expand Up @@ -104,10 +112,7 @@ public bool Equals(JFifMarker other)
}

/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is JFifMarker other && this.Equals(other);
}
public override bool Equals(object obj) => obj is JFifMarker other && this.Equals(other);

/// <inheritdoc/>
public override int GetHashCode()
Expand Down
21 changes: 21 additions & 0 deletions src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,25 @@ public JpegComponent(MemoryAllocator memoryAllocator, JpegFrame frame, byte id,
this.memoryAllocator = memoryAllocator;
this.Frame = frame;
this.Id = id;

// Valid sampling factors are 1..2
if (horizontalFactor == 0
|| verticalFactor == 0
|| horizontalFactor > 2
|| verticalFactor > 2)
{
JpegThrowHelper.ThrowBadSampling();
}

this.HorizontalSamplingFactor = horizontalFactor;
this.VerticalSamplingFactor = verticalFactor;
this.SamplingFactors = new Size(this.HorizontalSamplingFactor, this.VerticalSamplingFactor);

if (quantizationTableIndex > 3)
{
JpegThrowHelper.ThrowBadQuantizationTable();
}

this.QuantizationTableIndex = quantizationTableIndex;
this.Index = index;
}
Expand Down Expand Up @@ -110,6 +126,11 @@ public void Init()
JpegComponent c0 = this.Frame.Components[0];
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);

if (this.SubSamplingDivisors.Width == 0 || this.SubSamplingDivisors.Height == 0)
{
JpegThrowHelper.ThrowBadSampling();
}

int totalNumberOfBlocks = blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
int width = this.WidthInBlocks + 1;
int height = totalNumberOfBlocks / width;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void Dispose()
{
for (int i = 0; i < this.Components.Length; i++)
{
this.Components[i].Dispose();
this.Components[i]?.Dispose();
}

this.Components = null;
Expand Down
62 changes: 52 additions & 10 deletions src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,60 @@ private void ParseBaselineDataNonInterleaved()
}
}

private void CheckProgressiveData()
{
// Validate successive scan parameters.
// Logic has been adapted from libjpeg.
// See Table B.3 – Scan header parameter size and values. itu-t81.pdf
bool invalid = false;
if (this.spectralStart == 0)
{
if (this.spectralEnd != 0)
{
invalid = true;
}
}
else
{
// Need not check Ss/Se < 0 since they came from unsigned bytes.
if (this.spectralEnd < this.spectralStart || this.spectralEnd > 63)
{
invalid = true;
}

// AC scans may have only one component.
if (this.componentsLength != 1)
{
invalid = true;
}
}

if (this.successiveHigh != 0)
{
// Successive approximation refinement scan: must have Al = Ah-1.
if (this.successiveHigh - 1 != this.successiveLow)
{
invalid = true;
}
}

// TODO: How does this affect 12bit jpegs.
// According to libjpeg the range covers 8bit only?
if (this.successiveLow > 13)
{
invalid = true;
}

if (invalid)
{
JpegThrowHelper.ThrowBadProgressiveScan(this.spectralStart, this.spectralEnd, this.successiveHigh, this.successiveLow);
}
}

private void ParseProgressiveData()
{
this.CheckProgressiveData();

if (this.componentsLength == 1)
{
this.ParseProgressiveDataNonInterleaved();
Expand Down Expand Up @@ -483,11 +535,6 @@ private void DecodeBlockProgressiveDC(
ref Block8x8 block,
ref HuffmanTable dcTable)
{
if (this.spectralEnd != 0)
{
JpegThrowHelper.ThrowImageFormatException("Can't merge DC and AC.");
}

this.CheckBits();

ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);
Expand Down Expand Up @@ -518,11 +565,6 @@ private void DecodeBlockProgressiveAC(
ref HuffmanTable acTable,
ref short fastACRef)
{
if (this.spectralStart == 0)
{
JpegThrowHelper.ThrowImageFormatException("Can't merge DC and AC.");
}

ref short blockDataRef = ref Unsafe.As<Block8x8, short>(ref block);

if (this.successiveHigh == 0)
Expand Down
Loading