From: Greg Beaver Date: Fri, 20 Feb 2009 05:06:37 +0000 (+0000) Subject: fix zip access to work in all compilers, present and future, and on all arches withou... X-Git-Tag: RELEASE_1_3_5~79 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2344d800155018bc2284161b9318d7fa79cb8533;p=php fix zip access to work in all compilers, present and future, and on all arches without potential for bus errors. This removes PHAR_ZIP_PACK in favor of a safer approach --- diff --git a/ext/phar/phar.c b/ext/phar/phar.c index 44ca1ae75e..fab1b89974 100644 --- a/ext/phar/phar.c +++ b/ext/phar/phar.c @@ -510,19 +510,6 @@ void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC) /* {{{ */ var = ((((unsigned char*)(buffer))[1]) << 8) \ | (((unsigned char*)(buffer))[0]); \ (buffer) += 2 -static inline php_uint32 phar_fix_32(php_uint32 buffer) -{ - return ((((unsigned char *)&buffer)[3]) << 24) | - ((((unsigned char *)&buffer)[2]) << 16) | - ((((unsigned char *)&buffer)[1]) << 8) | - (((unsigned char *)&buffer)[0]); -} -static inline php_uint16 phar_fix_16(php_uint16 buffer) -{ - return ((((unsigned char *)&buffer)[1]) << 8) | ((unsigned char *)&buffer)[0]; -} -# define PHAR_ZIP_32(buffer) phar_fix_32((php_uint32)(buffer)) -# define PHAR_ZIP_16(buffer) phar_fix_16((php_uint16)(buffer)) #else # define PHAR_GET_32(buffer, var) \ var = *(php_uint32*)(buffer); \ @@ -530,9 +517,13 @@ static inline php_uint16 phar_fix_16(php_uint16 buffer) # define PHAR_GET_16(buffer, var) \ var = *(php_uint16*)(buffer); \ buffer += 2 -# define PHAR_ZIP_32(buffer) buffer -# define PHAR_ZIP_16(buffer) buffer #endif +#define PHAR_ZIP_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \ + (((php_uint16)var[1]) & 0xff) << 8)) +#define PHAR_ZIP_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \ + (((php_uint32)var[1]) & 0xff) << 8 | \ + (((php_uint32)var[2]) & 0xff) << 16 | \ + (((php_uint32)var[3]) & 0xff) << 24)) /** * Open an already loaded phar @@ -2420,7 +2411,7 @@ int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error /* verify local header */ if (entry->filename_len != PHAR_ZIP_16(local.filename_len) || entry->crc32 != PHAR_ZIP_32(local.crc32) || entry->uncompressed_filesize != PHAR_ZIP_32(local.uncompsize) || entry->compressed_filesize != PHAR_ZIP_32(local.compsize)) { - spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local head of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename); + spprintf(error, 0, "phar error: internal corruption of zip-based phar \"%s\" (local header of file \"%s\" does not match central directory)", idata->phar->fname, entry->filename); return FAILURE; } diff --git a/ext/phar/pharzip.h b/ext/phar/pharzip.h index b0ee2b2a10..47307d49c3 100644 --- a/ext/phar/pharzip.h +++ b/ext/phar/pharzip.h @@ -19,59 +19,43 @@ /* $Id$ */ -#ifdef PHP_WIN32 -#pragma pack(1) -# define PHAR_ZIP_PACK -#elif defined(__sgi) -# define PHAR_ZIP_PACK -#else -# define PHAR_ZIP_PACK __attribute__((__packed__)) -#endif - -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_file_header { char signature[4]; /* local file header signature 4 bytes (0x04034b50) */ char zipversion[2]; /* version needed to extract 2 bytes */ - php_uint16 flags; /* general purpose bit flag 2 bytes */ - php_uint16 compressed; /* compression method 2 bytes */ - php_uint16 timestamp; /* last mod file time 2 bytes */ - php_uint16 datestamp; /* last mod file date 2 bytes */ - php_uint32 crc32; /* crc-32 4 bytes */ - php_uint32 compsize; /* compressed size 4 bytes */ - php_uint32 uncompsize; /* uncompressed size 4 bytes */ - php_uint16 filename_len; /* file name length 2 bytes */ - php_uint16 extra_len; /* extra field length 2 bytes */ + char flags[2]; /* general purpose bit flag 2 bytes */ + char compressed[2]; /* compression method 2 bytes */ + char timestamp[2]; /* last mod file time 2 bytes */ + char datestamp[2]; /* last mod file date 2 bytes */ + char crc32[4]; /* crc-32 4 bytes */ + char compsize[4]; /* compressed size 4 bytes */ + char uncompsize[4]; /* uncompressed size 4 bytes */ + char filename_len[2]; /* file name length 2 bytes */ + char extra_len[2]; /* extra field length 2 bytes */ /* file name (variable size) */ /* extra field (variable size) */ -} PHAR_ZIP_PACK phar_zip_file_header; +} phar_zip_file_header; -#if defined(__sgi) -# pragma pack 0 -#endif +/* unused in this release */ typedef struct _phar_zip_file_datadesc { - php_uint32 crc32; /* crc-32 4 bytes */ - php_uint32 compsize; /* compressed size 4 bytes */ - php_uint32 uncompsize; /* uncompressed size 4 bytes */ -} PHAR_ZIP_PACK phar_zip_data_desc; + char crc32[4]; /* crc-32 4 bytes */ + char compsize[4]; /* compressed size 4 bytes */ + char uncompsize[4]; /* uncompressed size 4 bytes */ +} phar_zip_data_desc; +/* unused in this release */ typedef struct _phar_zip_file_datadesc_zip64 { - php_uint32 crc32; /* crc-32 4 bytes */ - php_uint32 compsize; /* compressed size 8 bytes */ - php_uint32 compsize2; - php_uint32 uncompsize; /* uncompressed size 8 bytes */ - php_uint32 uncompsize2; -} PHAR_ZIP_PACK phar_zip_data_desc_zip64; + char crc32[4]; /* crc-32 4 bytes */ + char compsize[4]; /* compressed size 8 bytes */ + char compsize2[4]; + char uncompsize[4]; /* uncompressed size 8 bytes */ + char uncompsize2[4]; +} phar_zip_data_desc_zip64; -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_archive_extra_data_record { char signature[4]; /* archive extra data signature 4 bytes (0x08064b50) */ - php_uint32 len; /* extra field length 4 bytes */ + char len[4]; /* extra field length 4 bytes */ /* extra field data (variable size) */ -} PHAR_ZIP_PACK phar_zip_archive_extra_data_record; +} phar_zip_archive_extra_data_record; /* madeby/extractneeded value if bzip2 compression is used */ #define PHAR_ZIP_BZIP2 "46" @@ -147,129 +131,107 @@ typedef struct _phar_zip_archive_extra_data_record { the CRC; i.e., it may be four bytes too small.] */ -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_extra_field_header { char tag[2]; - php_uint16 size; -} PHAR_ZIP_PACK phar_zip_extra_field_header; + char size[2]; +} phar_zip_extra_field_header; -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_unix3 { char tag[2]; /* 0x756e Short tag for this extra block type ("nu") */ - php_uint16 size; /* TSize Short total data size for this block */ - php_uint32 crc32; /* CRC Long CRC-32 of the remaining data */ - php_uint16 perms; /* Mode Short file permissions */ - php_uint32 symlinksize; /* SizDev Long symlink'd size OR major/minor dev num */ - php_uint16 uid; /* UID Short user ID */ - php_uint16 gid; /* GID Short group ID */ + char size[2]; /* TSize Short total data size for this block */ + char crc32[4]; /* CRC Long CRC-32 of the remaining data */ + char perms[2]; /* Mode Short file permissions */ + char symlinksize[4]; /* SizDev Long symlink'd size OR major/minor dev num */ + char uid[2]; /* UID Short user ID */ + char gid[2]; /* GID Short group ID */ /* (var.) variable symbolic link filename */ -} PHAR_ZIP_PACK phar_zip_unix3; +} phar_zip_unix3; -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_central_dir_file { char signature[4]; /* central file header signature 4 bytes (0x02014b50) */ char madeby[2]; /* version made by 2 bytes */ char zipversion[2]; /* version needed to extract 2 bytes */ - php_uint16 flags; /* general purpose bit flag 2 bytes */ - php_uint16 compressed; /* compression method 2 bytes */ - php_uint16 timestamp; /* last mod file time 2 bytes */ - php_uint16 datestamp; /* last mod file date 2 bytes */ - php_uint32 crc32; /* crc-32 4 bytes */ - php_uint32 compsize; /* compressed size 4 bytes */ - php_uint32 uncompsize; /* uncompressed size 4 bytes */ - php_uint16 filename_len; /* file name length 2 bytes */ - php_uint16 extra_len; /* extra field length 2 bytes */ - php_uint16 comment_len; /* file comment length 2 bytes */ - php_uint16 disknumber; /* disk number start 2 bytes */ - php_uint16 internal_atts; /* internal file attributes 2 bytes */ - php_uint32 external_atts; /* external file attributes 4 bytes */ - php_uint32 offset; /* relative offset of local header 4 bytes */ + char flags[2]; /* general purpose bit flag 2 bytes */ + char compressed[2]; /* compression method 2 bytes */ + char timestamp[2]; /* last mod file time 2 bytes */ + char datestamp[2]; /* last mod file date 2 bytes */ + char crc32[4]; /* crc-32 4 bytes */ + char compsize[4]; /* compressed size 4 bytes */ + char uncompsize[4]; /* uncompressed size 4 bytes */ + char filename_len[2]; /* file name length 2 bytes */ + char extra_len[2]; /* extra field length 2 bytes */ + char comment_len[2]; /* file comment length 2 bytes */ + char disknumber[2]; /* disk number start 2 bytes */ + char internal_atts[2]; /* internal file attributes 2 bytes */ + char external_atts[4]; /* external file attributes 4 bytes */ + char offset[4]; /* relative offset of local header 4 bytes */ /* file name (variable size) */ /* extra field (variable size) */ /* file comment (variable size) */ -} PHAR_ZIP_PACK phar_zip_central_dir_file; +} phar_zip_central_dir_file; -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_dir_signature { char signature[4]; /* header signature 4 bytes (0x05054b50) */ - php_uint16 size; /* size of data 2 bytes */ -} PHAR_ZIP_PACK phar_zip_dir_signature; + char size[2]; /* size of data 2 bytes */ +} phar_zip_dir_signature; -#if defined(__sgi) -# pragma pack 0 -#endif +/* unused in this release */ typedef struct _phar_zip64_dir_end { char signature[4]; /* zip64 end of central dir signature 4 bytes (0x06064b50) */ - php_uint32 size1; /* size of zip64 end of central + char size1[4]; /* size of zip64 end of central directory record 8 bytes */ - php_uint32 size2; + char size2[4]; char madeby[2]; /* version made by 2 bytes */ - php_uint16 extractneeded; /* version needed to extract 2 bytes */ - php_uint32 disknum; /* number of this disk 4 bytes */ - php_uint32 cdir_num; /* number of the disk with the + char extractneeded[2]; /* version needed to extract 2 bytes */ + char disknum[4]; /* number of this disk 4 bytes */ + char cdir_num[4]; /* number of the disk with the start of the central directory 4 bytes */ - php_uint32 entries1; /* total number of entries in the + char entries1[4]; /* total number of entries in the central directory on this disk 8 bytes */ - php_uint32 entries2; - php_uint32 entriestotal1; /* total number of entries in the + char entries2[4]; + char entriestotal1[4]; /* total number of entries in the central directory 8 bytes */ - php_uint32 entriestotal2; - php_uint32 cdirsize1; /* size of the central directory 8 bytes */ - php_uint32 cdirsize2; - php_uint32 offset1; /* offset of start of central + char entriestotal2[4]; + char cdirsize1[4]; /* size of the central directory 8 bytes */ + char cdirsize2[4]; + char offset1[4]; /* offset of start of central directory with respect to the starting disk number 8 bytes */ - php_uint32 offset2; + char offset2[4]; /* zip64 extensible data sector (variable size) */ -} PHAR_ZIP_PACK phar_zip64_dir_end; +} phar_zip64_dir_end; -#if defined(__sgi) -# pragma pack 0 -#endif +/* unused in this release */ typedef struct _phar_zip64_dir_locator { char signature[4]; /* zip64 end of central dir locator signature 4 bytes (0x07064b50) */ - php_uint32 disknum; /* number of the disk with the + char disknum[4]; /* number of the disk with the start of the zip64 end of central directory 4 bytes */ - php_uint32 diroffset1; /* relative offset of the zip64 + char diroffset1[4]; /* relative offset of the zip64 end of central directory record 8 bytes */ - php_uint32 diroffset2; - php_uint32 totaldisks; /* total number of disks 4 bytes */ -} PHAR_ZIP_PACK phar_zip64_dir_locator; + char diroffset2[4]; + char totaldisks[4]; /* total number of disks 4 bytes */ +} phar_zip64_dir_locator; -#if defined(__sgi) -# pragma pack 0 -#endif typedef struct _phar_zip_dir_end { char signature[4]; /* end of central dir signature 4 bytes (0x06054b50) */ - php_uint16 disknumber; /* number of this disk 2 bytes */ - php_uint16 centraldisk; /* number of the disk with the + char disknumber[2]; /* number of this disk 2 bytes */ + char centraldisk[2]; /* number of the disk with the start of the central directory 2 bytes */ - php_uint16 counthere; /* total number of entries in the + char counthere[2]; /* total number of entries in the central directory on this disk 2 bytes */ - php_uint16 count; /* total number of entries in + char count[2]; /* total number of entries in the central directory 2 bytes */ - php_uint32 cdir_size; /* size of the central directory 4 bytes */ - php_uint32 cdir_offset; /* offset of start of central + char cdir_size[4]; /* size of the central directory 4 bytes */ + char cdir_offset[4]; /* offset of start of central directory with respect to the starting disk number 4 bytes */ - php_uint16 comment_len; /* .ZIP file comment length 2 bytes */ + char comment_len[2]; /* .ZIP file comment length 2 bytes */ /* .ZIP file comment (variable size) */ -} PHAR_ZIP_PACK phar_zip_dir_end; -#ifdef PHP_WIN32 -#pragma pack() -#endif +} phar_zip_dir_end; /* * Local variables: * tab-width: 4 diff --git a/ext/phar/zip.c b/ext/phar/zip.c index 528e95c2ad..dd90aad0fd 100644 --- a/ext/phar/zip.c +++ b/ext/phar/zip.c @@ -18,28 +18,26 @@ #include "phar_internal.h" -#ifdef WORDS_BIGENDIAN -static inline php_uint32 phar_fix_32(php_uint32 buffer) +#define PHAR_GET_16(var) ((php_uint16)((((php_uint16)var[0]) & 0xff) | \ + (((php_uint16)var[1]) & 0xff) << 8)) +#define PHAR_GET_32(var) ((php_uint32)((((php_uint32)var[0]) & 0xff) | \ + (((php_uint32)var[1]) & 0xff) << 8 | \ + (((php_uint32)var[2]) & 0xff) << 16 | \ + (((php_uint32)var[3]) & 0xff) << 24)) +static inline void phar_write_32(char buffer[4], php_uint32 value) { - return ((((unsigned char *)&buffer)[3]) << 24) | - ((((unsigned char *)&buffer)[2]) << 16) | - ((((unsigned char *)&buffer)[1]) << 8) | - (((unsigned char *)&buffer)[0]); + buffer[3] = (unsigned char) ((value & 0xff000000) >> 24); + buffer[2] = (unsigned char) ((value & 0xff0000) >> 16); + buffer[1] = (unsigned char) ((value & 0xff00) >> 8); + buffer[0] = (unsigned char) (value & 0xff); } -static inline php_uint16 phar_fix_16(php_uint16 buffer) +static inline void phar_write_16(char buffer[2], php_uint32 value) { - return ((((unsigned char *)&buffer)[1]) << 8) | ((unsigned char *)&buffer)[0]; + buffer[1] = (unsigned char) ((value & 0xff00) >> 8); + buffer[0] = (unsigned char) (value & 0xff); } -# define PHAR_GET_32(buffer) phar_fix_32((php_uint32)(buffer)) -# define PHAR_GET_16(buffer) phar_fix_16((php_uint16)(buffer)) -# define PHAR_SET_32(buffer) PHAR_GET_32(buffer) -# define PHAR_SET_16(buffer) PHAR_GET_16(buffer) -#else -# define PHAR_GET_32(buffer) (buffer) -# define PHAR_GET_16(buffer) (buffer) -# define PHAR_SET_32(buffer) (buffer) -# define PHAR_SET_16(buffer) (buffer) -#endif +# define PHAR_SET_32(var, value) phar_write_32(var, (php_uint32) (value)); +# define PHAR_SET_16(var, value) phar_write_16(var, (php_uint16) (value)); static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_uint16 len TSRMLS_DC) /* {{{ */ { @@ -71,7 +69,7 @@ static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_ui if (PHAR_GET_16(h.unix3.size) > sizeof(h.unix3) - 4) { /* skip symlink filename - we may add this support in later */ - php_stream_seek(fp, h.unix3.size - sizeof(h.unix3.size), SEEK_CUR); + php_stream_seek(fp, PHAR_GET_16(h.unix3.size) - sizeof(h.unix3.size), SEEK_CUR); } /* set permissions */ @@ -122,8 +120,9 @@ static int phar_zip_process_extra(php_stream *fp, phar_entry_info *entry, php_ui OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -static time_t phar_zip_d2u_time(int dtime, int ddate) /* {{{ */ +static time_t phar_zip_d2u_time(char *cdtime, char *cddate) /* {{{ */ { + int dtime = PHAR_GET_16(cdtime), ddate = PHAR_GET_16(cddate); struct tm *tm, tmbuf; time_t now; @@ -142,13 +141,16 @@ static time_t phar_zip_d2u_time(int dtime, int ddate) /* {{{ */ } /* }}} */ -static void phar_zip_u2d_time(time_t time, php_uint16 *dtime, php_uint16 *ddate) /* {{{ */ +static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */ { + php_uint16 ctime, cdate; struct tm *tm, tmbuf; tm = php_localtime_r(&time, &tmbuf); - *ddate = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday; - *dtime = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1); + ctime = ((tm->tm_year+1900-1980)<<9) + ((tm->tm_mon+1)<<5) + tm->tm_mday; + cdate = ((tm->tm_hour)<<11) + ((tm->tm_min)<<5) + ((tm->tm_sec)>>1); + PHAR_SET_16(dtime, ctime); + PHAR_SET_16(ddate, cdate); } /* }}} */ @@ -198,7 +200,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) { if (!memcmp(p + 1, "K\5\6", 3)) { memcpy((void *)&locator, (void *) p, sizeof(locator)); - if (locator.centraldisk != 0 || locator.disknumber != 0) { + if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) { /* split archives not handled */ php_stream_close(fp); if (error) { @@ -207,7 +209,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, return FAILURE; } - if (locator.counthere != locator.count) { + if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) { if (error) { spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname); } @@ -219,7 +221,7 @@ int phar_parse_zipfile(php_stream *fp, char *fname, int fname_len, char *alias, mydata->is_persistent = PHAR_G(persist); /* read in archive comment, if any */ - if (locator.comment_len) { + if (PHAR_GET_16(locator.comment_len)) { char *metadata; metadata = p + sizeof(locator); @@ -443,7 +445,7 @@ foundit: } /* get file metadata */ - if (zipentry.comment_len) { + if (PHAR_GET_16(zipentry.comment_len)) { if (PHAR_GET_16(zipentry.comment_len) != php_stream_read(fp, buf, PHAR_GET_16(zipentry.comment_len))) { pefree(entry.filename, entry.is_persistent); PHAR_ZIP_FAIL("unable to read in file comment, truncated"); @@ -487,7 +489,7 @@ foundit: /* verify local header */ if (entry.filename_len != PHAR_GET_16(local.filename_len) || entry.crc32 != PHAR_GET_32(local.crc32) || entry.uncompressed_filesize != PHAR_GET_32(local.uncompsize) || entry.compressed_filesize != PHAR_GET_32(local.compsize)) { pefree(entry.filename, entry.is_persistent); - PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (local head of alias does not match central directory)"); + PHAR_ZIP_FAIL("phar error: internal corruption of zip-based phar (local header of alias does not match central directory)"); } /* construct actual offset to file start - local extra_len can be different from central extra_len */ @@ -718,30 +720,36 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */ memset(&perms, 0, sizeof(perms)); strncpy(local.signature, "PK\3\4", 4); strncpy(central.signature, "PK\1\2", 4); - central.extra_len = local.extra_len = PHAR_SET_16(sizeof(perms)); + PHAR_SET_16(central.extra_len, sizeof(perms)); + PHAR_SET_16(local.extra_len, sizeof(perms)); perms.tag[0] = 'n'; perms.tag[1] = 'u'; - perms.size = PHAR_SET_16(sizeof(perms) - 4); - perms.perms = PHAR_SET_16(entry->flags & PHAR_ENT_PERM_MASK); - perms.crc32 = ~0; - CRC32(perms.crc32, (char)perms.perms & 0xFF); - CRC32(perms.crc32, (char)perms.perms & 0xFF00 >> 8); - perms.crc32 = PHAR_SET_32(~(perms.crc32)); + PHAR_SET_16(perms.size, sizeof(perms) - 4); + PHAR_SET_16(perms.perms, entry->flags & PHAR_ENT_PERM_MASK); + { + php_uint32 crc = ~0; + CRC32(crc, perms.perms[0]); + CRC32(crc, perms.perms[1]); + PHAR_SET_32(perms.crc32, ~crc); + } if (entry->flags & PHAR_ENT_COMPRESSED_GZ) { - local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_DEFLATE); + PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_DEFLATE); + PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_DEFLATE); } if (entry->flags & PHAR_ENT_COMPRESSED_BZ2) { - local.compressed = central.compressed = PHAR_SET_16(PHAR_ZIP_COMP_BZIP2); + PHAR_SET_16(central.compressed, PHAR_ZIP_COMP_BZIP2); + PHAR_SET_16(local.compressed, PHAR_ZIP_COMP_BZIP2); } - /* do not use PHAR_SET_16 on either field of the next line */ - phar_zip_u2d_time(entry->timestamp, &local.timestamp, &local.datestamp); - central.timestamp = local.timestamp; - central.datestamp = local.datestamp; - central.filename_len = local.filename_len = PHAR_SET_16(entry->filename_len + (entry->is_dir ? 1 : 0)); - central.offset = PHAR_SET_32(php_stream_tell(p->filefp)); + /* do not use PHAR_GET_16 on either field of the next line */ + phar_zip_u2d_time(entry->timestamp, local.timestamp, local.datestamp); + memcpy(central.timestamp, local.timestamp, sizeof(local.timestamp)); + memcpy(central.datestamp, local.datestamp, sizeof(local.datestamp)); + PHAR_SET_16(central.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0)); + PHAR_SET_16(local.filename_len, entry->filename_len + (entry->is_dir ? 1 : 0)); + PHAR_SET_32(central.offset, php_stream_tell(p->filefp)); /* do extra field for perms later */ if (entry->is_modified) { @@ -783,12 +791,14 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */ } entry->crc32 = ~newcrc32; - central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize); + PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize); + PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize); if (!(entry->flags & PHAR_ENT_COMPRESSION_MASK)) { /* not compressed */ entry->compressed_filesize = entry->uncompressed_filesize; - central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); + PHAR_SET_32(central.compsize, entry->uncompressed_filesize); + PHAR_SET_32(local.compsize, entry->uncompressed_filesize); goto not_compressed; } @@ -832,15 +842,18 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */ php_stream_filter_remove(filter, 1 TSRMLS_CC); php_stream_seek(entry->cfp, 0, SEEK_END); entry->compressed_filesize = (php_uint32) php_stream_tell(entry->cfp); - central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); + PHAR_SET_32(central.compsize, entry->compressed_filesize); + PHAR_SET_32(local.compsize, entry->compressed_filesize); /* generate crc on compressed file */ php_stream_rewind(entry->cfp); entry->old_flags = entry->flags; entry->is_modified = 1; } else { is_compressed: - central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize); - central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize); + PHAR_SET_32(central.uncompsize, entry->uncompressed_filesize); + PHAR_SET_32(local.uncompsize, entry->uncompressed_filesize); + PHAR_SET_32(central.compsize, entry->compressed_filesize); + PHAR_SET_32(local.compsize, entry->compressed_filesize); if (-1 == php_stream_seek(p->old, entry->offset_abs, SEEK_SET)) { spprintf(p->error, 0, "unable to seek to start of file \"%s\" while creating zip-based phar \"%s\"", entry->filename, entry->phar->fname); @@ -848,7 +861,8 @@ is_compressed: } } not_compressed: - central.crc32 = local.crc32 = PHAR_SET_32(entry->crc32); + PHAR_SET_32(central.crc32, entry->crc32); + PHAR_SET_32(local.crc32, entry->crc32); continue_dir: /* set file metadata */ if (entry->metadata) { @@ -862,7 +876,7 @@ continue_dir: PHP_VAR_SERIALIZE_INIT(metadata_hash); php_var_serialize(&entry->metadata_str, &entry->metadata, &metadata_hash TSRMLS_CC); PHP_VAR_SERIALIZE_DESTROY(metadata_hash); - central.comment_len = PHAR_SET_16(entry->metadata_str.len); + PHAR_SET_16(central.comment_len, entry->metadata_str.len); } entry->header_offset = php_stream_tell(p->filefp); @@ -1200,7 +1214,8 @@ fperror: memset(&eocd, 0, sizeof(eocd)); strncpy(eocd.signature, "PK\5\6", 4); - eocd.counthere = eocd.count = PHAR_GET_16(zend_hash_num_elements(&phar->manifest)); + PHAR_SET_16(eocd.counthere, zend_hash_num_elements(&phar->manifest)); + PHAR_SET_16(eocd.count, zend_hash_num_elements(&phar->manifest)); zend_hash_apply_with_argument(&phar->manifest, phar_zip_changed_apply, (void *) &pass TSRMLS_CC); if (temperr) { @@ -1221,8 +1236,8 @@ nocentralerror: /* save zip */ cdir_size = php_stream_tell(pass.centralfp); cdir_offset = php_stream_tell(pass.filefp); - eocd.cdir_size = PHAR_SET_32(cdir_size); - eocd.cdir_offset = PHAR_SET_32(cdir_offset); + PHAR_SET_32(eocd.cdir_size, cdir_size); + PHAR_SET_32(eocd.cdir_offset, cdir_offset); php_stream_seek(pass.centralfp, 0, SEEK_SET); if (cdir_size != php_stream_copy_to_stream(pass.centralfp, pass.filefp, PHP_STREAM_COPY_ALL)) { @@ -1239,7 +1254,7 @@ nocentralerror: PHP_VAR_SERIALIZE_INIT(metadata_hash); php_var_serialize(&main_metadata_str, &phar->metadata, &metadata_hash TSRMLS_CC); PHP_VAR_SERIALIZE_DESTROY(metadata_hash); - eocd.comment_len = PHAR_SET_16(main_metadata_str.len); + PHAR_SET_16(eocd.comment_len, main_metadata_str.len); if (sizeof(eocd) != php_stream_write(pass.filefp, (char *)&eocd, sizeof(eocd))) { if (error) {