@@ -638,6 +638,18 @@ int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_
638
638
}
639
639
/* }}}*/
640
640
641
+ /**
642
+ * Size of fixed fields in the manifest.
643
+ * See: http://php.net/manual/en/phar.fileformat.phar.php
644
+ */
645
+ #define MANIFEST_FIXED_LEN 18
646
+
647
+ #define SAFE_PHAR_GET_32 (buffer , endbuffer , var ) \
648
+ if (UNEXPECTED(buffer + 4 > endbuffer)) { \
649
+ MAPPHAR_FAIL("internal corruption of phar \"%s\" (truncated manifest header)"); \
650
+ } \
651
+ PHAR_GET_32(buffer, var);
652
+
641
653
/**
642
654
* Does not check for a previously opened phar in the cache.
643
655
*
@@ -721,12 +733,12 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
721
733
savebuf = buffer ;
722
734
endbuffer = buffer + manifest_len ;
723
735
724
- if (manifest_len < 10 || manifest_len != php_stream_read (fp , buffer , manifest_len )) {
736
+ if (manifest_len < MANIFEST_FIXED_LEN || manifest_len != php_stream_read (fp , buffer , manifest_len )) {
725
737
MAPPHAR_FAIL ("internal corruption of phar \"%s\" (truncated manifest header)" )
726
738
}
727
739
728
740
/* extract the number of entries */
729
- PHAR_GET_32 (buffer , manifest_count );
741
+ SAFE_PHAR_GET_32 (buffer , endbuffer , manifest_count );
730
742
731
743
if (manifest_count == 0 ) {
732
744
MAPPHAR_FAIL ("in phar \"%s\", manifest claims to have zero entries. Phars must have at least 1 entry" );
@@ -746,7 +758,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
746
758
return FAILURE ;
747
759
}
748
760
749
- PHAR_GET_32 (buffer , manifest_flags );
761
+ SAFE_PHAR_GET_32 (buffer , endbuffer , manifest_flags );
750
762
751
763
manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK ;
752
764
manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK ;
@@ -966,13 +978,13 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
966
978
}
967
979
968
980
/* extract alias */
969
- PHAR_GET_32 (buffer , tmp_len );
981
+ SAFE_PHAR_GET_32 (buffer , endbuffer , tmp_len );
970
982
971
983
if (buffer + tmp_len > endbuffer ) {
972
984
MAPPHAR_FAIL ("internal corruption of phar \"%s\" (buffer overrun)" );
973
985
}
974
986
975
- if (manifest_len < 10 + tmp_len ) {
987
+ if (manifest_len < MANIFEST_FIXED_LEN + tmp_len ) {
976
988
MAPPHAR_FAIL ("internal corruption of phar \"%s\" (truncated manifest header)" )
977
989
}
978
990
@@ -1010,7 +1022,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
1010
1022
}
1011
1023
1012
1024
/* we have 5 32-bit items plus 1 byte at least */
1013
- if (manifest_count > ((manifest_len - 10 - tmp_len ) / (5 * 4 + 1 ))) {
1025
+ if (manifest_count > ((manifest_len - MANIFEST_FIXED_LEN - tmp_len ) / (5 * 4 + 1 ))) {
1014
1026
/* prevent serious memory issues */
1015
1027
MAPPHAR_FAIL ("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)" )
1016
1028
}
@@ -1019,12 +1031,12 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
1019
1031
mydata -> is_persistent = PHAR_G (persist );
1020
1032
1021
1033
/* check whether we have meta data, zero check works regardless of byte order */
1022
- PHAR_GET_32 (buffer , len );
1034
+ SAFE_PHAR_GET_32 (buffer , endbuffer , len );
1023
1035
if (mydata -> is_persistent ) {
1024
1036
mydata -> metadata_len = len ;
1025
- if (!len ) {
1037
+ if (!len ) {
1026
1038
/* FIXME: not sure why this is needed but removing it breaks tests */
1027
- PHAR_GET_32 (buffer , len );
1039
+ SAFE_PHAR_GET_32 (buffer , endbuffer , len );
1028
1040
}
1029
1041
}
1030
1042
if (len > endbuffer - buffer ) {
0 commit comments