@@ -638,6 +638,18 @@ int phar_parse_metadata(char **buffer, zval **metadata, php_uint32 zip_metadata_
638638}
639639/* }}}*/
640640
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+
641653/**
642654 * Does not check for a previously opened phar in the cache.
643655 *
@@ -721,12 +733,12 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
721733 savebuf = buffer ;
722734 endbuffer = buffer + manifest_len ;
723735
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 )) {
725737 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (truncated manifest header)" )
726738 }
727739
728740 /* extract the number of entries */
729- PHAR_GET_32 (buffer , manifest_count );
741+ SAFE_PHAR_GET_32 (buffer , endbuffer , manifest_count );
730742
731743 if (manifest_count == 0 ) {
732744 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
746758 return FAILURE ;
747759 }
748760
749- PHAR_GET_32 (buffer , manifest_flags );
761+ SAFE_PHAR_GET_32 (buffer , endbuffer , manifest_flags );
750762
751763 manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK ;
752764 manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK ;
@@ -966,13 +978,13 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
966978 }
967979
968980 /* extract alias */
969- PHAR_GET_32 (buffer , tmp_len );
981+ SAFE_PHAR_GET_32 (buffer , endbuffer , tmp_len );
970982
971983 if (buffer + tmp_len > endbuffer ) {
972984 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (buffer overrun)" );
973985 }
974986
975- if (manifest_len < 10 + tmp_len ) {
987+ if (manifest_len < MANIFEST_FIXED_LEN + tmp_len ) {
976988 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (truncated manifest header)" )
977989 }
978990
@@ -1010,7 +1022,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
10101022 }
10111023
10121024 /* 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 ))) {
10141026 /* prevent serious memory issues */
10151027 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)" )
10161028 }
@@ -1019,12 +1031,12 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
10191031 mydata -> is_persistent = PHAR_G (persist );
10201032
10211033 /* 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 );
10231035 if (mydata -> is_persistent ) {
10241036 mydata -> metadata_len = len ;
1025- if (!len ) {
1037+ if (!len ) {
10261038 /* 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 );
10281040 }
10291041 }
10301042 if (len > endbuffer - buffer ) {
0 commit comments