@@ -161,6 +161,29 @@ static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */
161161}
162162/* }}} */
163163
164+ static char * phar_find_eocd (const char * s , size_t n )
165+ {
166+ const char * end = s + n + sizeof ("PK\5\6" ) - 1 - sizeof (phar_zip_dir_end );
167+
168+ /* search backwards for end of central directory signatures */
169+ do {
170+ uint16_t comment_len ;
171+ const char * eocd_start = zend_memnrstr (s , "PK\5\6" , sizeof ("PK\5\6" ) - 1 , end );
172+
173+ if (eocd_start == NULL ) {
174+ return NULL ;
175+ }
176+ ZEND_ASSERT (eocd_start + sizeof (phar_zip_dir_end ) <= s + n );
177+ comment_len = PHAR_GET_16 (((phar_zip_dir_end * ) eocd_start )-> comment_len );
178+ if (eocd_start + sizeof (phar_zip_dir_end ) + comment_len == s + n ) {
179+ /* we can't be sure, but this looks like the proper EOCD signature */
180+ return (char * ) eocd_start ;
181+ }
182+ end = eocd_start ;
183+ } while (end > s );
184+ return NULL ;
185+ }
186+
164187/**
165188 * Does not check for a previously opened phar in the cache.
166189 *
@@ -205,50 +228,48 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia
205228 return FAILURE ;
206229 }
207230
208- while ((p = (char * ) memchr (p + 1 , 'P' , (size_t ) (size - (p + 1 - buf )))) != NULL ) {
209- if ((p - buf ) + sizeof (locator ) <= (size_t )size && !memcmp (p + 1 , "K\5\6" , 3 )) {
210- memcpy ((void * )& locator , (void * ) p , sizeof (locator ));
211- if (PHAR_GET_16 (locator .centraldisk ) != 0 || PHAR_GET_16 (locator .disknumber ) != 0 ) {
212- /* split archives not handled */
213- php_stream_close (fp );
214- if (error ) {
215- spprintf (error , 4096 , "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"" , fname );
216- }
217- return FAILURE ;
231+ if ((p = phar_find_eocd (buf , size )) != NULL ) {
232+ memcpy ((void * )& locator , (void * ) p , sizeof (locator ));
233+ if (PHAR_GET_16 (locator .centraldisk ) != 0 || PHAR_GET_16 (locator .disknumber ) != 0 ) {
234+ /* split archives not handled */
235+ php_stream_close (fp );
236+ if (error ) {
237+ spprintf (error , 4096 , "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"" , fname );
218238 }
239+ return FAILURE ;
240+ }
219241
220- if (PHAR_GET_16 (locator .counthere ) != PHAR_GET_16 (locator .count )) {
221- if (error ) {
222- spprintf (error , 4096 , "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"" , fname );
223- }
224- php_stream_close (fp );
225- return FAILURE ;
242+ if (PHAR_GET_16 (locator .counthere ) != PHAR_GET_16 (locator .count )) {
243+ if (error ) {
244+ spprintf (error , 4096 , "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"" , fname );
226245 }
246+ php_stream_close (fp );
247+ return FAILURE ;
248+ }
227249
228- mydata = pecalloc (1 , sizeof (phar_archive_data ), PHAR_G (persist ));
229- mydata -> is_persistent = PHAR_G (persist );
250+ mydata = pecalloc (1 , sizeof (phar_archive_data ), PHAR_G (persist ));
251+ mydata -> is_persistent = PHAR_G (persist );
230252
231- /* read in archive comment, if any */
232- if (PHAR_GET_16 (locator .comment_len )) {
253+ /* read in archive comment, if any */
254+ if (PHAR_GET_16 (locator .comment_len )) {
233255
234- metadata = p + sizeof (locator );
256+ metadata = p + sizeof (locator );
235257
236- if (PHAR_GET_16 (locator .comment_len ) != size - (metadata - buf )) {
237- if (error ) {
238- spprintf (error , 4096 , "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"" , fname );
239- }
240- php_stream_close (fp );
241- pefree (mydata , mydata -> is_persistent );
242- return FAILURE ;
258+ if (PHAR_GET_16 (locator .comment_len ) != size - (metadata - buf )) {
259+ if (error ) {
260+ spprintf (error , 4096 , "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"" , fname );
243261 }
244-
245- phar_parse_metadata_lazy (metadata , & mydata -> metadata_tracker , PHAR_GET_16 (locator .comment_len ), mydata -> is_persistent );
246- } else {
247- ZVAL_UNDEF (& mydata -> metadata_tracker .val );
262+ php_stream_close (fp );
263+ pefree (mydata , mydata -> is_persistent );
264+ return FAILURE ;
248265 }
249266
250- goto foundit ;
267+ phar_parse_metadata_lazy (metadata , & mydata -> metadata_tracker , PHAR_GET_16 (locator .comment_len ), mydata -> is_persistent );
268+ } else {
269+ ZVAL_UNDEF (& mydata -> metadata_tracker .val );
251270 }
271+
272+ goto foundit ;
252273 }
253274
254275 php_stream_close (fp );
0 commit comments