@@ -228,28 +228,41 @@ public void LoadTables(byte[] tableBytes, HuffmanScanDecoder huffmanScanDecoder)
228228 this . Metadata = new ImageMetadata ( ) ;
229229 this . QuantizationTables = new Block8x8F [ 4 ] ;
230230 this . scanDecoder = huffmanScanDecoder ;
231+
232+ if ( tableBytes . Length < 4 )
233+ {
234+ JpegThrowHelper . ThrowInvalidImageContentException ( "Not enough data to read marker" ) ;
235+ }
236+
231237 using var ms = new MemoryStream ( tableBytes ) ;
232238 using var stream = new BufferedReadStream ( this . Configuration , ms ) ;
233239
234240 // Check for the Start Of Image marker.
235- stream . Read ( this . markerBuffer , 0 , 2 ) ;
241+ int bytesRead = stream . Read ( this . markerBuffer , 0 , 2 ) ;
236242 var fileMarker = new JpegFileMarker ( this . markerBuffer [ 1 ] , 0 ) ;
237243 if ( fileMarker . Marker != JpegConstants . Markers . SOI )
238244 {
239245 JpegThrowHelper . ThrowInvalidImageContentException ( "Missing SOI marker." ) ;
240246 }
241247
242248 // Read next marker.
243- stream . Read ( this . markerBuffer , 0 , 2 ) ;
244- byte marker = this . markerBuffer [ 1 ] ;
245- fileMarker = new JpegFileMarker ( marker , ( int ) stream . Position - 2 ) ;
249+ bytesRead = stream . Read ( this . markerBuffer , 0 , 2 ) ;
250+ fileMarker = new JpegFileMarker ( this . markerBuffer [ 1 ] , ( int ) stream . Position - 2 ) ;
246251
247252 while ( fileMarker . Marker != JpegConstants . Markers . EOI || ( fileMarker . Marker == JpegConstants . Markers . EOI && fileMarker . Invalid ) )
248253 {
249254 if ( ! fileMarker . Invalid )
250255 {
251256 // Get the marker length.
252- int remaining = this . ReadUint16 ( stream ) - 2 ;
257+ int markerContentByteSize = this . ReadUint16 ( stream ) - 2 ;
258+
259+ // Check whether stream actually has enought bytes to read
260+ // markerContentByteSize is always positive so we cast
261+ // to uint to avoid sign extension
262+ if ( stream . RemainingBytes < ( uint ) markerContentByteSize )
263+ {
264+ JpegThrowHelper . ThrowNotEnoughBytesForMarker ( fileMarker . Marker ) ;
265+ }
253266
254267 switch ( fileMarker . Marker )
255268 {
@@ -259,21 +272,26 @@ public void LoadTables(byte[] tableBytes, HuffmanScanDecoder huffmanScanDecoder)
259272 case JpegConstants . Markers . RST7 :
260273 break ;
261274 case JpegConstants . Markers . DHT :
262- this . ProcessDefineHuffmanTablesMarker ( stream , remaining ) ;
275+ this . ProcessDefineHuffmanTablesMarker ( stream , markerContentByteSize ) ;
263276 break ;
264277 case JpegConstants . Markers . DQT :
265- this . ProcessDefineQuantizationTablesMarker ( stream , remaining ) ;
278+ this . ProcessDefineQuantizationTablesMarker ( stream , markerContentByteSize ) ;
266279 break ;
267280 case JpegConstants . Markers . DRI :
268- this . ProcessDefineRestartIntervalMarker ( stream , remaining ) ;
281+ this . ProcessDefineRestartIntervalMarker ( stream , markerContentByteSize ) ;
269282 break ;
270283 case JpegConstants . Markers . EOI :
271284 return ;
272285 }
273286 }
274287
275288 // Read next marker.
276- stream . Read ( this . markerBuffer , 0 , 2 ) ;
289+ bytesRead = stream . Read ( this . markerBuffer , 0 , 2 ) ;
290+ if ( bytesRead != 2 )
291+ {
292+ JpegThrowHelper . ThrowInvalidImageContentException ( "Not enough data to read marker" ) ;
293+ }
294+
277295 fileMarker = new JpegFileMarker ( this . markerBuffer [ 1 ] , 0 ) ;
278296 }
279297 }
@@ -730,7 +748,14 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
730748
731749 if ( ProfileResolver . IsProfile ( this . temp , ProfileResolver . XmpMarker . Slice ( 0 , ExifMarkerLength ) ) )
732750 {
733- int remainingXmpMarkerBytes = XmpMarkerLength - ExifMarkerLength ;
751+ const int remainingXmpMarkerBytes = XmpMarkerLength - ExifMarkerLength ;
752+ if ( remaining < remainingXmpMarkerBytes || this . IgnoreMetadata )
753+ {
754+ // Skip the application header length.
755+ stream . Skip ( remaining ) ;
756+ return ;
757+ }
758+
734759 stream . Read ( this . temp , ExifMarkerLength , remainingXmpMarkerBytes ) ;
735760 remaining -= remainingXmpMarkerBytes ;
736761 if ( ProfileResolver . IsProfile ( this . temp , ProfileResolver . XmpMarker ) )
@@ -1320,8 +1345,12 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
13201345 component . ACHuffmanTableId = acTableIndex ;
13211346 }
13221347
1323- // 3 bytes: Progressive scan decoding data
1324- stream . Read ( this . temp , 0 , 3 ) ;
1348+ // 3 bytes: Progressive scan decoding data.
1349+ int bytesRead = stream . Read ( this . temp , 0 , 3 ) ;
1350+ if ( bytesRead != 3 )
1351+ {
1352+ JpegThrowHelper . ThrowInvalidImageContentException ( "Not enough data to read progressive scan decoding data" ) ;
1353+ }
13251354
13261355 int spectralStart = this . temp [ 0 ] ;
13271356 this . scanDecoder . SpectralStart = spectralStart ;
@@ -1344,7 +1373,12 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
13441373 [ MethodImpl ( InliningOptions . ShortMethod ) ]
13451374 private ushort ReadUint16 ( BufferedReadStream stream )
13461375 {
1347- stream . Read ( this . markerBuffer , 0 , 2 ) ;
1376+ int bytesRead = stream . Read ( this . markerBuffer , 0 , 2 ) ;
1377+ if ( bytesRead != 2 )
1378+ {
1379+ JpegThrowHelper . ThrowInvalidImageContentException ( "jpeg stream does not contain enough data, could not read ushort." ) ;
1380+ }
1381+
13481382 return BinaryPrimitives . ReadUInt16BigEndian ( this . markerBuffer ) ;
13491383 }
13501384 }
0 commit comments