Skip to content

Commit c5f14f7

Browse files
Merge branch 'main' into js/decode-sanitation
2 parents 4a32c75 + 5d0c684 commit c5f14f7

File tree

6 files changed

+41
-16
lines changed

6 files changed

+41
-16
lines changed

src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -330,14 +330,22 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco
330330
if (!fileMarker.Invalid)
331331
{
332332
// Get the marker length.
333-
int remaining = this.ReadUint16(stream) - 2;
333+
int markerContentByteSize = this.ReadUint16(stream) - 2;
334+
335+
// Check whether stream actually has enought bytes to read
336+
// markerContentByteSize is always positive so we cast
337+
// to uint to avoid sign extension
338+
if (stream.RemainingBytes < (uint)markerContentByteSize)
339+
{
340+
JpegThrowHelper.ThrowNotEnoughBytesForMarker(fileMarker.Marker);
341+
}
334342

335343
switch (fileMarker.Marker)
336344
{
337345
case JpegConstants.Markers.SOF0:
338346
case JpegConstants.Markers.SOF1:
339347
case JpegConstants.Markers.SOF2:
340-
this.ProcessStartOfFrameMarker(stream, remaining, fileMarker, metadataOnly);
348+
this.ProcessStartOfFrameMarker(stream, markerContentByteSize, fileMarker, metadataOnly);
341349
break;
342350

343351
case JpegConstants.Markers.SOF5:
@@ -365,7 +373,7 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco
365373
case JpegConstants.Markers.SOS:
366374
if (!metadataOnly)
367375
{
368-
this.ProcessStartOfScanMarker(stream, remaining);
376+
this.ProcessStartOfScanMarker(stream, markerContentByteSize);
369377
break;
370378
}
371379
else
@@ -379,41 +387,41 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco
379387

380388
if (metadataOnly)
381389
{
382-
stream.Skip(remaining);
390+
stream.Skip(markerContentByteSize);
383391
}
384392
else
385393
{
386-
this.ProcessDefineHuffmanTablesMarker(stream, remaining);
394+
this.ProcessDefineHuffmanTablesMarker(stream, markerContentByteSize);
387395
}
388396

389397
break;
390398

391399
case JpegConstants.Markers.DQT:
392-
this.ProcessDefineQuantizationTablesMarker(stream, remaining);
400+
this.ProcessDefineQuantizationTablesMarker(stream, markerContentByteSize);
393401
break;
394402

395403
case JpegConstants.Markers.DRI:
396404
if (metadataOnly)
397405
{
398-
stream.Skip(remaining);
406+
stream.Skip(markerContentByteSize);
399407
}
400408
else
401409
{
402-
this.ProcessDefineRestartIntervalMarker(stream, remaining);
410+
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize);
403411
}
404412

405413
break;
406414

407415
case JpegConstants.Markers.APP0:
408-
this.ProcessApplicationHeaderMarker(stream, remaining);
416+
this.ProcessApplicationHeaderMarker(stream, markerContentByteSize);
409417
break;
410418

411419
case JpegConstants.Markers.APP1:
412-
this.ProcessApp1Marker(stream, remaining);
420+
this.ProcessApp1Marker(stream, markerContentByteSize);
413421
break;
414422

415423
case JpegConstants.Markers.APP2:
416-
this.ProcessApp2Marker(stream, remaining);
424+
this.ProcessApp2Marker(stream, markerContentByteSize);
417425
break;
418426

419427
case JpegConstants.Markers.APP3:
@@ -426,20 +434,20 @@ internal void ParseStream(BufferedReadStream stream, HuffmanScanDecoder scanDeco
426434
case JpegConstants.Markers.APP10:
427435
case JpegConstants.Markers.APP11:
428436
case JpegConstants.Markers.APP12:
429-
stream.Skip(remaining);
437+
stream.Skip(markerContentByteSize);
430438
break;
431439

432440
case JpegConstants.Markers.APP13:
433-
this.ProcessApp13Marker(stream, remaining);
441+
this.ProcessApp13Marker(stream, markerContentByteSize);
434442
break;
435443

436444
case JpegConstants.Markers.APP14:
437-
this.ProcessApp14Marker(stream, remaining);
445+
this.ProcessApp14Marker(stream, markerContentByteSize);
438446
break;
439447

440448
case JpegConstants.Markers.APP15:
441449
case JpegConstants.Markers.COM:
442-
stream.Skip(remaining);
450+
stream.Skip(markerContentByteSize);
443451
break;
444452

445453
case JpegConstants.Markers.DAC:
@@ -1282,7 +1290,7 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
12821290
int selectorsBytes = selectorsCount * 2;
12831291
if (remaining != 4 + selectorsBytes)
12841292
{
1285-
JpegThrowHelper.ThrowBadMarker("SOS", remaining);
1293+
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.SOS), remaining);
12861294
}
12871295

12881296
// selectorsCount*2 bytes: component index + huffman tables indices

src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ internal static class JpegThrowHelper
2525
[MethodImpl(InliningOptions.ColdPath)]
2626
public static void ThrowBadMarker(string marker, int length) => throw new InvalidImageContentException($"Marker {marker} has bad length {length}.");
2727

28+
[MethodImpl(InliningOptions.ColdPath)]
29+
public static void ThrowNotEnoughBytesForMarker(byte marker) => throw new InvalidImageContentException($"Input stream does not have enough bytes to parse declared contents of the {marker:X2} marker.");
30+
2831
[MethodImpl(InliningOptions.ColdPath)]
2932
public static void ThrowBadQuantizationTableIndex(int index) => throw new InvalidImageContentException($"Bad Quantization Table index {index}.");
3033

src/ImageSharp/IO/BufferedReadStream.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ public override long Position
114114
/// <inheritdoc/>
115115
public override bool CanWrite { get; } = false;
116116

117+
/// <summary>
118+
/// Gets remaining byte count available to read.
119+
/// </summary>
120+
public long RemainingBytes
121+
{
122+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
123+
get => this.Length - this.Position;
124+
}
125+
117126
/// <summary>
118127
/// Gets the underlying stream.
119128
/// </summary>

tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public partial class JpegDecoderTests
105105
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693A,
106106
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException1693B,
107107
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824C,
108+
TestImages.Jpeg.Issues.Fuzz.NullReferenceException2085,
108109
};
109110

110111
private static readonly Dictionary<string, float> CustomToleranceValues = new()

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ public static class Fuzz
292292
public const string AccessViolationException922 = "Jpg/issues/fuzz/Issue922-AccessViolationException.jpg";
293293
public const string IndexOutOfRangeException1693A = "Jpg/issues/fuzz/Issue1693-IndexOutOfRangeException-A.jpg";
294294
public const string IndexOutOfRangeException1693B = "Jpg/issues/fuzz/Issue1693-IndexOutOfRangeException-B.jpg";
295+
public const string NullReferenceException2085 = "Jpg/issues/fuzz/Issue2085-NullReferenceException.jpg";
295296
}
296297
}
297298

Lines changed: 3 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)