@@ -642,6 +642,18 @@ int phar_parse_metadata(char **buffer, zval *metadata, uint32_t zip_metadata_len
642642}
643643/* }}}*/
644644
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+
645657/**
646658 * Does not check for a previously opened phar in the cache.
647659 *
@@ -725,12 +737,12 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
725737 savebuf = buffer ;
726738 endbuffer = buffer + manifest_len ;
727739
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 )) {
729741 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (truncated manifest header)" )
730742 }
731743
732744 /* extract the number of entries */
733- PHAR_GET_32 (buffer , manifest_count );
745+ SAFE_PHAR_GET_32 (buffer , endbuffer , manifest_count );
734746
735747 if (manifest_count == 0 ) {
736748 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
750762 return FAILURE ;
751763 }
752764
753- PHAR_GET_32 (buffer , manifest_flags );
765+ SAFE_PHAR_GET_32 (buffer , endbuffer , manifest_flags );
754766
755767 manifest_flags &= ~PHAR_HDR_COMPRESSION_MASK ;
756768 manifest_flags &= ~PHAR_FILE_COMPRESSION_MASK ;
@@ -970,13 +982,13 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
970982 }
971983
972984 /* extract alias */
973- PHAR_GET_32 (buffer , tmp_len );
985+ SAFE_PHAR_GET_32 (buffer , endbuffer , tmp_len );
974986
975987 if (buffer + tmp_len > endbuffer ) {
976988 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (buffer overrun)" );
977989 }
978990
979- if (manifest_len < 10 + tmp_len ) {
991+ if (manifest_len < MANIFEST_FIXED_LEN + tmp_len ) {
980992 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (truncated manifest header)" )
981993 }
982994
@@ -1014,7 +1026,7 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
10141026 }
10151027
10161028 /* 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 ))) {
10181030 /* prevent serious memory issues */
10191031 MAPPHAR_FAIL ("internal corruption of phar \"%s\" (too many manifest entries for size of manifest)" )
10201032 }
@@ -1023,12 +1035,12 @@ static int phar_parse_pharfile(php_stream *fp, char *fname, int fname_len, char
10231035 mydata -> is_persistent = PHAR_G (persist );
10241036
10251037 /* 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 );
10271039 if (mydata -> is_persistent ) {
10281040 mydata -> metadata_len = len ;
1029- if (!len ) {
1041+ if (!len ) {
10301042 /* 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 );
10321044 }
10331045 }
10341046 if (len > (size_t )(endbuffer - buffer )) {
0 commit comments