@@ -39,19 +39,30 @@ static inline void phar_write_16(char buffer[2], uint32_t value)
3939# define PHAR_SET_32 (var , value ) phar_write_32(var, (uint32_t) (value));
4040# define PHAR_SET_16 (var , value ) phar_write_16(var, (uint16_t) (value));
4141
42- static zend_result phar_zip_process_extra (php_stream * fp , phar_entry_info * entry , uint16_t len ) /* {{{ */
42+ static zend_result phar_zip_process_extra (php_stream * fp , phar_entry_info * entry , uint16_t extra_len ) /* {{{ */
4343{
4444 union {
4545 phar_zip_extra_field_header header ;
4646 phar_zip_unix3 unix3 ;
4747 phar_zip_unix_time time ;
4848 } h ;
49+ size_t len = extra_len ;
4950 size_t read ;
5051
51- do {
52+ while (len ) {
53+ size_t header_size ;
54+
55+ if (len < sizeof (h .header )) {
56+ return FAILURE ;
57+ }
5258 if (sizeof (h .header ) != php_stream_read (fp , (char * ) & h .header , sizeof (h .header ))) {
5359 return FAILURE ;
5460 }
61+ len -= sizeof (h .header );
62+ header_size = PHAR_GET_16 (h .header .size );
63+ if (header_size > len ) {
64+ return FAILURE ;
65+ }
5566
5667 if (h .header .tag [0 ] == 'U' && h .header .tag [1 ] == 'T' ) {
5768 /* Unix timestamp header found.
@@ -60,7 +71,6 @@ static zend_result phar_zip_process_extra(php_stream *fp, phar_entry_info *entry
6071 * We only store the modification time in the entry, so only read that.
6172 */
6273 const size_t min_size = 5 ;
63- uint16_t header_size = PHAR_GET_16 (h .header .size );
6474 if (header_size >= min_size ) {
6575 read = php_stream_read (fp , & h .time .flags , min_size );
6676 if (read != min_size ) {
@@ -71,36 +81,48 @@ static zend_result phar_zip_process_extra(php_stream *fp, phar_entry_info *entry
7181 entry -> timestamp = PHAR_GET_32 (h .time .time );
7282 }
7383
74- len -= header_size + 4 ;
75-
7684 /* Consume remaining bytes */
77- if (header_size != read ) {
78- php_stream_seek ( fp , header_size - read , SEEK_CUR ) ;
85+ if (header_size != read && -1 == php_stream_seek ( fp , header_size - read , SEEK_CUR ) ) {
86+ return FAILURE ;
7987 }
88+ len -= header_size ;
8089 continue ;
8190 }
8291 /* Fallthrough to next if to skip header */
8392 }
8493
8594 if (h .header .tag [0 ] != 'n' || h .header .tag [1 ] != 'u' ) {
8695 /* skip to next header */
87- php_stream_seek (fp , PHAR_GET_16 (h .header .size ), SEEK_CUR );
88- len -= PHAR_GET_16 (h .header .size ) + 4 ;
96+ if (header_size && -1 == php_stream_seek (fp , header_size , SEEK_CUR )) {
97+ return FAILURE ;
98+ }
99+ len -= header_size ;
89100 continue ;
90101 }
91102
92103 /* unix3 header found */
93- read = php_stream_read (fp , (char * ) & (h .unix3 .crc32 ), sizeof (h .unix3 ) - sizeof (h .header ));
94- len -= read + 4 ;
104+ size_t unix3_size = sizeof (h .unix3 ) - sizeof (h .header );
105+ size_t field_size = header_size ;
106+ if (field_size == unix3_size - sizeof (h .unix3 .crc32 )) {
107+ /* Some archives omit the CRC32 from the unix3 size field. */
108+ field_size = unix3_size ;
109+ }
110+ if (field_size < unix3_size || field_size > len ) {
111+ return FAILURE ;
112+ }
95113
96- if (sizeof (h .unix3 ) - sizeof (h .header ) != read ) {
114+ read = php_stream_read (fp , (char * ) & (h .unix3 .crc32 ), unix3_size );
115+ if (unix3_size != read ) {
97116 return FAILURE ;
98117 }
99118
100- if (PHAR_GET_16 ( h . unix3 . size ) > sizeof ( h . unix3 ) - 4 ) {
119+ if (field_size > unix3_size ) {
101120 /* skip symlink filename - we may add this support in later */
102- php_stream_seek (fp , PHAR_GET_16 (h .unix3 .size ) - sizeof (h .unix3 .size ), SEEK_CUR );
121+ if (-1 == php_stream_seek (fp , field_size - unix3_size , SEEK_CUR )) {
122+ return FAILURE ;
123+ }
103124 }
125+ len -= field_size ;
104126
105127 /* set permissions */
106128 entry -> flags &= PHAR_ENT_COMPRESSION_MASK ;
@@ -111,7 +133,7 @@ static zend_result phar_zip_process_extra(php_stream *fp, phar_entry_info *entry
111133 entry -> flags |= PHAR_GET_16 (h .unix3 .perms ) & PHAR_ENT_PERM_MASK ;
112134 }
113135
114- } while ( len );
136+ }
115137
116138 return SUCCESS ;
117139}
0 commit comments