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