@@ -215,6 +215,25 @@ zend_module_entry exif_module_entry = {
215
215
ZEND_GET_MODULE (exif )
216
216
#endif
217
217
218
+ /* php_stream_read() may return early without reading all data, depending on the chunk size
219
+ * and whether it's a URL stream or not. This helper keeps reading until the requested amount
220
+ * is read or until there is no more data available to read. */
221
+ static ssize_t exif_read_from_stream_file_looped (php_stream * stream , char * buf , size_t count )
222
+ {
223
+ ssize_t total_read = 0 ;
224
+ while (total_read < count ) {
225
+ ssize_t ret = php_stream_read (stream , buf + total_read , count - total_read );
226
+ if (ret == -1 ) {
227
+ return -1 ;
228
+ }
229
+ if (ret == 0 ) {
230
+ break ;
231
+ }
232
+ total_read += ret ;
233
+ }
234
+ return total_read ;
235
+ }
236
+
218
237
/* {{{ php_strnlen
219
238
* get length of string if buffer if less than buffer size or buffer size */
220
239
static size_t php_strnlen (char * str , size_t maxlen ) {
@@ -3321,7 +3340,7 @@ static bool exif_process_IFD_TAG_impl(image_info_type *ImageInfo, char *dir_entr
3321
3340
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Wrong file pointer: 0x%08X != 0x%08X" , fgot , displacement + offset_val );
3322
3341
return false;
3323
3342
}
3324
- fgot = php_stream_read (ImageInfo -> infile , value_ptr , byte_count );
3343
+ fgot = exif_read_from_stream_file_looped (ImageInfo -> infile , value_ptr , byte_count );
3325
3344
php_stream_seek (ImageInfo -> infile , fpos , SEEK_SET );
3326
3345
if (fgot != byte_count ) {
3327
3346
EFREE_IF (outside );
@@ -3854,7 +3873,7 @@ static bool exif_scan_JPEG_header(image_info_type *ImageInfo)
3854
3873
Data [0 ] = (uchar )lh ;
3855
3874
Data [1 ] = (uchar )ll ;
3856
3875
3857
- got = php_stream_read (ImageInfo -> infile , (char * )(Data + 2 ), itemlen - 2 ); /* Read the whole section. */
3876
+ got = exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(Data + 2 ), itemlen - 2 ); /* Read the whole section. */
3858
3877
if (got != itemlen - 2 ) {
3859
3878
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Error reading from file: got=x%04X(=%d) != itemlen-2=x%04X(=%d)" , got , got , itemlen - 2 , itemlen - 2 );
3860
3879
return false;
@@ -3872,7 +3891,7 @@ static bool exif_scan_JPEG_header(image_info_type *ImageInfo)
3872
3891
size = ImageInfo -> FileSize - fpos ;
3873
3892
sn = exif_file_sections_add (ImageInfo , M_PSEUDO , size , NULL );
3874
3893
Data = ImageInfo -> file .list [sn ].data ;
3875
- got = php_stream_read (ImageInfo -> infile , (char * )Data , size );
3894
+ got = exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )Data , size );
3876
3895
if (got != size ) {
3877
3896
EXIF_ERRLOG_FILEEOF (ImageInfo )
3878
3897
return false ;
@@ -4049,7 +4068,9 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir
4049
4068
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_NOTICE , "Read from TIFF: filesize(x%04X), IFD dir(x%04X + x%04X)" , ImageInfo -> FileSize , dir_offset , 2 );
4050
4069
#endif
4051
4070
php_stream_seek (ImageInfo -> infile , dir_offset , SEEK_SET ); /* we do not know the order of sections */
4052
- php_stream_read (ImageInfo -> infile , (char * )ImageInfo -> file .list [sn ].data , 2 );
4071
+ if (UNEXPECTED (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )ImageInfo -> file .list [sn ].data , 2 ) != 2 )) {
4072
+ return false;
4073
+ }
4053
4074
num_entries = php_ifd_get16u (ImageInfo -> file .list [sn ].data , ImageInfo -> motorola_intel );
4054
4075
dir_size = 2 /*num dir entries*/ + 12 /*length of entry*/ * (size_t )num_entries + 4 /* offset to next ifd (points to thumbnail or NULL)*/ ;
4055
4076
if (ImageInfo -> FileSize >= dir_size && ImageInfo -> FileSize - dir_size >= dir_offset ) {
@@ -4059,7 +4080,9 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir
4059
4080
if (exif_file_sections_realloc (ImageInfo , sn , dir_size )) {
4060
4081
return false;
4061
4082
}
4062
- php_stream_read (ImageInfo -> infile , (char * )(ImageInfo -> file .list [sn ].data + 2 ), dir_size - 2 );
4083
+ if (UNEXPECTED (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(ImageInfo -> file .list [sn ].data + 2 ), dir_size - 2 ) != dir_size - 2 )) {
4084
+ return false;
4085
+ }
4063
4086
next_offset = php_ifd_get32u (ImageInfo -> file .list [sn ].data + dir_size - 4 , ImageInfo -> motorola_intel );
4064
4087
#ifdef EXIF_DEBUG
4065
4088
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_NOTICE , "Read from TIFF done, next offset x%04X" , next_offset );
@@ -4147,7 +4170,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir
4147
4170
#ifdef EXIF_DEBUG
4148
4171
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_NOTICE , "Read from TIFF: filesize(x%04X), IFD(x%04X + x%04X)" , ImageInfo -> FileSize , dir_offset , ifd_size );
4149
4172
#endif
4150
- php_stream_read (ImageInfo -> infile , (char * )(ImageInfo -> file .list [sn ].data + dir_size ), ifd_size - dir_size );
4173
+ exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(ImageInfo -> file .list [sn ].data + dir_size ), ifd_size - dir_size );
4151
4174
#ifdef EXIF_DEBUG
4152
4175
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_NOTICE , "Read from TIFF , done ");
4153
4176
#endif
@@ -4198,7 +4221,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir
4198
4221
if (!ImageInfo -> Thumbnail .data ) {
4199
4222
ImageInfo -> Thumbnail .data = safe_emalloc (ImageInfo -> Thumbnail .size , 1 , 0 );
4200
4223
php_stream_seek (ImageInfo -> infile , ImageInfo -> Thumbnail .offset , SEEK_SET );
4201
- fgot = php_stream_read (ImageInfo -> infile , ImageInfo -> Thumbnail .data , ImageInfo -> Thumbnail .size );
4224
+ fgot = exif_read_from_stream_file_looped (ImageInfo -> infile , ImageInfo -> Thumbnail .data , ImageInfo -> Thumbnail .size );
4202
4225
if (fgot != ImageInfo -> Thumbnail .size ) {
4203
4226
EXIF_ERRLOG_THUMBEOF (ImageInfo )
4204
4227
efree (ImageInfo -> Thumbnail .data );
@@ -4238,7 +4261,7 @@ static bool exif_process_IFD_in_TIFF_impl(image_info_type *ImageInfo, size_t dir
4238
4261
if (!ImageInfo -> Thumbnail .data && ImageInfo -> Thumbnail .offset && ImageInfo -> Thumbnail .size && ImageInfo -> read_thumbnail ) {
4239
4262
ImageInfo -> Thumbnail .data = safe_emalloc (ImageInfo -> Thumbnail .size , 1 , 0 );
4240
4263
php_stream_seek (ImageInfo -> infile , ImageInfo -> Thumbnail .offset , SEEK_SET );
4241
- fgot = php_stream_read (ImageInfo -> infile , ImageInfo -> Thumbnail .data , ImageInfo -> Thumbnail .size );
4264
+ fgot = exif_read_from_stream_file_looped (ImageInfo -> infile , ImageInfo -> Thumbnail .data , ImageInfo -> Thumbnail .size );
4242
4265
if (fgot != ImageInfo -> Thumbnail .size ) {
4243
4266
EXIF_ERRLOG_THUMBEOF (ImageInfo )
4244
4267
efree (ImageInfo -> Thumbnail .data );
@@ -4293,7 +4316,7 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
4293
4316
4294
4317
if (ImageInfo -> FileSize >= 2 ) {
4295
4318
php_stream_seek (ImageInfo -> infile , 0 , SEEK_SET );
4296
- if (php_stream_read (ImageInfo -> infile , (char * )file_header , 2 ) != 2 ) {
4319
+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )file_header , 2 ) != 2 ) {
4297
4320
return false;
4298
4321
}
4299
4322
if ((file_header [0 ]== 0xff ) && (file_header [1 ]== M_SOI )) {
@@ -4304,7 +4327,7 @@ static bool exif_scan_FILE_header(image_info_type *ImageInfo)
4304
4327
exif_error_docref (NULL EXIFERR_CC , ImageInfo , E_WARNING , "Invalid JPEG file ");
4305
4328
}
4306
4329
} else if (ImageInfo -> FileSize >= 8 ) {
4307
- if (php_stream_read (ImageInfo -> infile , (char * )(file_header + 2 ), 6 ) != 6 ) {
4330
+ if (exif_read_from_stream_file_looped (ImageInfo -> infile , (char * )(file_header + 2 ), 6 ) != 6 ) {
4308
4331
return false;
4309
4332
}
4310
4333
if (!memcmp (file_header , "II\x2A\x00" , 4 )) {
0 commit comments