@@ -228,28 +228,41 @@ public void LoadTables(byte[] tableBytes, HuffmanScanDecoder huffmanScanDecoder)
228
228
this . Metadata = new ImageMetadata ( ) ;
229
229
this . QuantizationTables = new Block8x8F [ 4 ] ;
230
230
this . scanDecoder = huffmanScanDecoder ;
231
+
232
+ if ( tableBytes . Length < 4 )
233
+ {
234
+ JpegThrowHelper . ThrowInvalidImageContentException ( "Not enough data to read marker" ) ;
235
+ }
236
+
231
237
using var ms = new MemoryStream ( tableBytes ) ;
232
238
using var stream = new BufferedReadStream ( this . Configuration , ms ) ;
233
239
234
240
// Check for the Start Of Image marker.
235
- stream . Read ( this . markerBuffer , 0 , 2 ) ;
241
+ int bytesRead = stream . Read ( this . markerBuffer , 0 , 2 ) ;
236
242
var fileMarker = new JpegFileMarker ( this . markerBuffer [ 1 ] , 0 ) ;
237
243
if ( fileMarker . Marker != JpegConstants . Markers . SOI )
238
244
{
239
245
JpegThrowHelper . ThrowInvalidImageContentException ( "Missing SOI marker." ) ;
240
246
}
241
247
242
248
// 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 ) ;
246
251
247
252
while ( fileMarker . Marker != JpegConstants . Markers . EOI || ( fileMarker . Marker == JpegConstants . Markers . EOI && fileMarker . Invalid ) )
248
253
{
249
254
if ( ! fileMarker . Invalid )
250
255
{
251
256
// 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
+ }
253
266
254
267
switch ( fileMarker . Marker )
255
268
{
@@ -259,21 +272,26 @@ public void LoadTables(byte[] tableBytes, HuffmanScanDecoder huffmanScanDecoder)
259
272
case JpegConstants . Markers . RST7 :
260
273
break ;
261
274
case JpegConstants . Markers . DHT :
262
- this . ProcessDefineHuffmanTablesMarker ( stream , remaining ) ;
275
+ this . ProcessDefineHuffmanTablesMarker ( stream , markerContentByteSize ) ;
263
276
break ;
264
277
case JpegConstants . Markers . DQT :
265
- this . ProcessDefineQuantizationTablesMarker ( stream , remaining ) ;
278
+ this . ProcessDefineQuantizationTablesMarker ( stream , markerContentByteSize ) ;
266
279
break ;
267
280
case JpegConstants . Markers . DRI :
268
- this . ProcessDefineRestartIntervalMarker ( stream , remaining ) ;
281
+ this . ProcessDefineRestartIntervalMarker ( stream , markerContentByteSize ) ;
269
282
break ;
270
283
case JpegConstants . Markers . EOI :
271
284
return ;
272
285
}
273
286
}
274
287
275
288
// 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
+
277
295
fileMarker = new JpegFileMarker ( this . markerBuffer [ 1 ] , 0 ) ;
278
296
}
279
297
}
@@ -730,7 +748,14 @@ private void ProcessApp1Marker(BufferedReadStream stream, int remaining)
730
748
731
749
if ( ProfileResolver . IsProfile ( this . temp , ProfileResolver . XmpMarker . Slice ( 0 , ExifMarkerLength ) ) )
732
750
{
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
+
734
759
stream . Read ( this . temp , ExifMarkerLength , remainingXmpMarkerBytes ) ;
735
760
remaining -= remainingXmpMarkerBytes ;
736
761
if ( ProfileResolver . IsProfile ( this . temp , ProfileResolver . XmpMarker ) )
@@ -1320,8 +1345,12 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
1320
1345
component . ACHuffmanTableId = acTableIndex ;
1321
1346
}
1322
1347
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
+ }
1325
1354
1326
1355
int spectralStart = this . temp [ 0 ] ;
1327
1356
this . scanDecoder . SpectralStart = spectralStart ;
@@ -1344,7 +1373,12 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
1344
1373
[ MethodImpl ( InliningOptions . ShortMethod ) ]
1345
1374
private ushort ReadUint16 ( BufferedReadStream stream )
1346
1375
{
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
+
1348
1382
return BinaryPrimitives . ReadUInt16BigEndian ( this . markerBuffer ) ;
1349
1383
}
1350
1384
}
0 commit comments